算技@Python爬虫-商品信息(即将过期)

Python 实战-第 1 周-练习项目02-爬取商品信息

成果展示

week01-ex02-爬取商品信息

代码

贴代码如下。同时放在 GitHub 库

from bs4 import BeautifulSoup

finPath = "../../../Plan-for-combating-master/week1/1_2/\
1_2answer_of_homework/\
1_2_homework_required/index.html"

# Read and Analyse
with open(finPath, 'r') as fin:
    Soup = BeautifulSoup(fin.read(), 'lxml')
    itemTitle = Soup.select('body > div.container > div.row > div.col-md-9 > \
div.row > div > div > div.caption > h4:nth-of-type(2) > a')
    itemPicSrc = Soup.select('body > div.container > div.row > div.col-md-9 > \
div.row > div > div > img')
    itemPrice = Soup.select('body > div.container > div.row > div.col-md-9 > \
div.row > div > div > div.caption > h4.pull-right')
    itemComment = Soup.select('body > div.container > div.row > div.col-md-9 > \
div.row > div > div > div.ratings > p.pull-right')
    itemStar = Soup.select('body > div.container > div.row > div.col-md-9 > \
div.row > div > div > div.ratings > p:nth-of-type(2)')


# Save Result
dataSet = []

for iTitle, iPic, iPrice, iComment, iStar in zip(itemTitle, itemPicSrc, itemPrice, itemComment, itemStar):
    info = {
        'iTitle': iTitle.get_text(),
        'iPic': iPic.get('src'),
        'iPrice': iPrice.get_text(),
        'iComment': iComment.get_text(),
        'iStar': len(iStar.find_all("span", class_="glyphicon glyphicon-star"))
    }
    dataSet.append(info)

# See Result
for info in dataSet:
    print(info)

总结

0. 导入模块与文件

from bs4 import BeautifulSoup
# 若使用 from bs4 import BeautifulSoup as bs
# 则代码中所有 BeautifulSoup 均可替换成缩写 bs
with open(finPath, 'r') as fin:
# finPath 是 index.html 文件路径
# 以只读方式读取到变量 fin 中

1. 如何解析待爬取的网页

Soup = BeautifulSoup(fin.read(), 'lxml')
# 将从 fin 中读出的字符串(全文)解析为 lxml 格式

2. 直接拷贝通过 Chrome 「Inspect」(「检查」)得到的 CSS Selector 代码,作为 Soup.select() 的参数输入,得到空白列表

其中,作为 Soup.select() 参数的 CSS Selector 代码为

body > div:nth-child(2) > div > div.col-md-9 > div:nth-child(2) > div:nth-child(1) > div > div.caption > h4:nth-child(2) > a

解决方法

仅仅把 nth-child(num) 换成 nth-of-type(num) 是不起作用的。需要把大部分的 :nth-child(num) 换成用对应的CSS 类选择器才行

例如上述代码中 div:nth-child(2) 对应的 HTML 代码为 <div class = "container">blablabla</div>,那么这个 div 容器的 CSS 类选择器即为 container,从而要把 body > div:nth-child(2) 改为 body > div.container

其他部分如法炮制,除非某些标签不是靠类选择器来区分,例如这里最底层的 <h4></h4> 标签本身是没有类名的,因此仍然用 :nth-of-type(2) 定位。

最后修改 Soup.select() 的参数为如下字符串,从而得到所有包含标题的 <h4></h4> 标签

'body > div.container > div.row > div.col-md-9 > div.row > div > div > div.caption > h4:nth-of-type(2) > a'

3. 如何统计评分星级? 注意到「评价星级」并非是普通文本内容,无法直接通过 get_text() 或者 get() 得到

解决方法

查看网页中与评分星级有关的 HTML 代码发现,每一个星星,对应着一段这样的代码

<span class="glyphicon glyphicon-star"></span>

即 CSS 选择器 body > div.container > div.row > div.col-md-9 > \div.row > div > div > div.ratings > p:nth-of-type(2) 指向的位置的标签数为星级数。

那么如何计算标签数呢?如果能够找到这个位置下所有的标签,就有可能完成这一任务了。

幸运的是 BeautifulSoup 提供了这样一个方法:find_all(),该方法可根据搜索调用该方法的对象中是否有关键字所代表的标签;更棒的是该方法支持通过 按 CSS 搜索。因此我们可以编写下述 python 代码,首先将所有包含评分星级的 HTML 代码导入 itemStar 中,执行 print() 语句将展示 itemStar[0] 对应的评分星级数:

itemStar = Soup.select('body > div.container > div.row > div.col-md-9 > div.row > div > div > div.ratings > p:nth-of-type(2)')
print(len(itemStar[0].find_all("span", class_="glyphicon glyphicon-star")))

4. 如何保存结果?

爬取完毕后,或许需要保存爬取结果以便后续分析。这里我将爬取结果暂存于内存中(即不导出为文件)。

最开始我的代码是这样的:

for iTitle, iPic, iPrice, iComment, iStar in zip(itemTitle, itemPicSrc, itemPrice, itemComment, itemStar):
    info = {
        'iTitle': iTitle.get_text(),
        'iPic': iPic.get('src'),
        'iPrice': iPrice.get_text(),
        'iComment': iComment.get_text(),
        'iStar': len(iStar.find_all("span", class_="glyphicon glyphicon-star"))
    }

print(info)

然而为什么结果只有 1 项(5 个属性)?

解决办法

观察视频中源代码与自己代码在这部分的差别后,我发现:视频中的源代码是用一个列表保存结果的,而列表的每一项是一个字典。我的问题在于:每次循环时都更新名为 info 的字典,因此最后打印出的内容是最后一项商品信息。

知道了问题,于是修改代码如下:

# Save Result
dataSet = []

for iTitle, iPic, iPrice, iComment, iStar in zip(itemTitle, itemPicSrc, itemPrice, itemComment, itemStar):
    info = {
        'iTitle': iTitle.get_text(),
        'iPic': iPic.get('src'),
        'iPrice': iPrice.get_text(),
        'iComment': iComment.get_text(),
        'iStar': len(iStar.find_all("span", class_="glyphicon glyphicon-star"))
    }
    dataSet.append(info)

# See Result
for info in dataSet:
    print(info)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容