Python爬⾍(三)——数据解析
1. re模块
之前我们在python基础中介绍过正则表达式,⽽re模块可以使⽤正则表达式对字符串进⾏很好的筛选。re模块的使⽤可以分为两种:第⼀种是对象式的⽅式,第⼆种是函数式的⽅式。之前已经介绍过正则模块的简单使⽤,我们在这⾥就直接进⾏案例操作。
通过⽹页分析发现每⼀个图⽚的地址都被放在了该标签下。
在浏览器地址栏中输⼊该图⽚的地址就可以到这个图⽚。现在图⽚已经到了,下⼀步就是对图⽚进⾏下载。那么如何通过代码去实现呢?
url='fabiaoqing/biaoqing/lists/page/6.html'
(url).text
print(resp)
通过刚开始打印的控制台的内容发现浏览器中的代码结构与控制台打印的并不太⼀样。因此我们在⽹页源代码中查看
我们会发现每个图⽚的 URL 地址都在 data-original这个标签中,因此我们对该属性中的内容进⾏正则匹配,正则匹配规则为<img class="ui image lazy" data-original="(.*?)" 通过re.findall()来获得匹配到的内容,括号内的参数主要有三个,第⼀个是正则表达式,第⼆个是需要匹配的内容,第三个是匹配规则,在这⾥我们⼀般只需要记住第⼀个和第⼆个就可以了。
(url)
img_src=re.findall('<img class="ui image lazy" data-original="(.*?)"',,re.S)
匹配到的内容是⼀个列表,再遍历这个列表,依次对列表中的图⽚地址发送请求,因为是图⽚,所以它是⼆进制的形式,因此我们以⼆进制的形式进⾏保存,具体的完整代码请看⽂末附录⼀:
for src in img_src:
src_filename=src.rsplit('/')[-1]
img_(src)
with open(f'表情包\\第{page}页\\{src_filename}',mode='wb') as f:
f.write(t)
re模块对于新⼿来说,我们只需要记住表达式 .* ?就可以了,将需要匹配的内容以 .* ?的形式,re模块就会进⾏贪婪匹配。如果对于re模块想要深⼊了解的话⼤家可以对正则表达式那⼀部分的知识点进⾏深⼀步的了解。
2. css选择器
在学习css选择器之前还需要安装⼀个对应的库 parsel。这个库内置了很多的数据解析⽅式,⽐如常见的css解析、xpath解析以及re模块都是内置的,使⽤起来⼗分⽅便。
pip install parsel
如果学过前端三件套的话,那么对于css选择器的理解与使⽤应该是⾮常容易的。所谓css选择器,其实就是当我们在写css样式时需要对某⼀个具体的标签进⾏的定位。在使⽤css选择器之前需要先创建⼀个selector对象,所有的内容都以selector的形式来读取,如果想要获取具体的标签内容或者是属性内容,则需要特定的语法。
2.1 标签选择器
标签选择器就类似于js中的 getElementbyTagName()⼀样,通过直接对标签定位来对同⼀类型的标签加样式。常见的标签有 < div > 、< span >、< p >、< a > 等。通过直接绑定标签名称来获取标签。
import parsel
selector = parsel .selector(html)
span = selector.css( ' span ' ).getall()
print(span)
2.2 类选择器
类选择器就是通过标签中设定的class类来进⾏定位,定位到具有该类属性的标签,之后在进⾏获取。类的⽅式与css中的⽅式相同。
import parsel
selector = parsel .selector(html)
top = selector.css( '.top' ).getall()
print(top)
2.3 ID选择器
ID选择器在平时的使⽤中使⽤的⽐较多,因为同⼀个html⽂件中,id属性是唯⼀的,每⼀个id都对应⼀个标签,因此如果当获取的对象是唯⼀的,那么就可以使⽤id选择器。
import parse1
selector = parsel.selector(html)
p = selector.css ( ' #content ' ).geta11()
print(p)
2.4 组合选择器
在css进⾏样式修改时,如果权重不够,可以多个组合进⾏权重的增加,以此来让样式起到效果。
import parse1
selector = parsel.selector(html)
content = selector.css ( 'div .top' ).geta11()
print(content)
2.5 伪类选择器
伪类选择器在css样式的时候可能会多⼀点,但在爬⾍中使⽤的很少,⼏乎没有,所以我们只作为了解内容即可。
import parsel
selector = parse1.selector(htm1)
p = selector.css( 'p:nth-child(2) ').getall()
print(p)
2.6 属性提取器
⼤多数情况我们在使⽤css选择器的时候需要提取的是⽂本内容,⽐如标签中包含的⽂本或者是属性的内容,⽐如src属性中的url地址。⽽且属性提取器的使⽤也⾮常的⽅便与简洁。其中获取标签中包含的⽂本内容的语法是" p: :text ",使⽤两个冒号来作为区分,⽽获取标签的属性内容则为" p: :attr(href)" 括号中是需要获取的标签的属性。
import parse1
selector = parse1.selector(htm1)
# p::text是获取p标签的⽂本内容
p = selector.css( 'p: :text' ).geta11()
print(p)
# a::attr(href)是获取a标签的href属性
a = selector.css( 'a: :attr(href) ' ).getall()
print(a)
2.7 案例
上⾯已经介绍过css选择器的具体⽤法,下⾯让我们来给⼤家布置⼀个⼩任务:
使⽤ css 选择器将⾖瓣 250 的全部电影信息全部提取出来。
title(电影名)、 info(导演、主演、出版时间)、 score(评分)、follow(评价⼈数)
进⾏操作之前我们还是要对⽹站进⾏分析,先要确定所要获取的内容是否直接在⽹页上,然后再确定它的请求⽅式。之后才正式开始进⾏数据获取。通过分析发现,索要获取的内容都在⽹页上,那我们直接获取就可以了。
因为⾖瓣⽹站有相对的反扒机制,所以需要我们添加⼀些请求参数,需要将headers以及cookies都添加上才能获取到数据
url = f'movie.douban/top250?start={page}&filter='
headers = {
'Cookie': 'bid=nJ5mbBL3XUQ; __gads=ID=d4e33a95e1a5dad6-',
'Host': 'movie.douban',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36',    }
# 2. 发送请求
response = (url=url, headers=headers)
html_data =
print(html_data)
通过控制台打印的内容⽐对发现我们需要获取的内容确实就在⾥⾯,因此从获取到的内容中进⾏筛选,使⽤css选择器进⾏选择。
我们可以先获取所有的 li 标签,然后再遍历每个li标签,从中获取我们想要的相关信息。
selector = parsel.Selector(html_data)
python处理xml文件lis = selector.css('.grid_view li')  # 所有li标签
for li in lis:
title = li.css('.title::text').get()  //获取title⽂本
info = li.css('.bd p:nth-child(1)::text').getall()
score = li.css('.rating_num::text').get()
follow = li.css('.star span:nth-child(4)::text').get()
print(title, info, score, follow)
通过运⾏代码就可以发现我们已经将数据获取到了,对于获取的数据只需要做⼀些处理就是我们需要的数据。需要完整代码请直接到⽂末附录⼆。
3. xpath数据解析
3.1 认识xpath
XPath是⼀门再HTML\XML⽂档中查信息的语⾔,可⽤在HTML\XML⽂档中对元素和属性进⾏遍历
对于⼀些xml⽂件的内容和节点的遍历,我们可以使⽤xpath来获取。xml⽂件被⽤来传输和存储数据,也是由成对的标签组成,但标签是⾃定义的。xml主体呈现树状结构,跟html类似,也是有⽗⼦关系的标签,⽽节点与节点之间的关系就类似于我们⼈类⽣活中的族谱,有亲兄弟关系、⽗⼦关系、同级关系等。
3.2 xpath的语法
xpath中的常⽤语法主要就如下这些,掌握了这些对我们⽇常爬⾍也是⾜够了。在使⽤时与主要理清节点与节点之间的层级关系就可以了。
3.3 案例
⽬标⽹址: nba.hupu/stats/players/pts
需求:
1、⽤xpath采集 nba 球员数据
2、采集以下信息
rank  # 排名
player  # 球员
team    # 球队
score    # 得分
hit_shot  # 命中-出⼿
hit_rate  # 命中率
hit_three  # 命中-三分
three_rate  # 三分命中率
hit_penalty  # 命中-罚球
penalty_rate  # 罚球命中率
session  # 场次
playing_time  # 上场时间
做完准备⼯作后我们开始对该⽹站的数据进⾏获取。每⼀个球员的数据都放在⼀个< tr >标签⾥⾯,因此我们可以先获取所有的 < tr > 标签,然后再遍历每⼀个标签,并从中获取相关的内容。
selector = parsel.Selector(html_data)
trs = selector.xpath('//table[@class="players_table"]/tbody/tr')[1:]  # ⼆次提取
获取到所有的tr之后再遍历每⼀个tr,从中获取球员的各项数据
for tr in trs:
rank = tr.xpath('./td[1]/text()').get()  # 排名
player = tr.xpath('./td[2]/a/text()').get()  # 球员
team = tr.xpath('./td[3]/a/text()').get()  # 球队
score = tr.xpath('./td[4]/text()').get()  # 得分
hit_shot = tr.xpath('./td[5]/text()').get()  # 命中-出⼿
hit_rate = tr.xpath('./td[6]/text()').get()  # 命中率
hit_three = tr.xpath('./td[7]/text()').get()  # 命中-三分
three_rate = tr.xpath('./td[8]/text()').get()  # 三分命中率
hit_penalty = tr.xpath('./td[9]/text()').get()  # 命中-罚球
penalty_rate = tr.xpath('./td[10]/text()').get()  # 罚球命中率
session = tr.xpath('./td[11]/text()').get()  # 场次
playing_time = tr.xpath('./td[12]/text()').get()  # 上场时间
最后再将结果打印出来:
完整代码放在⽂末附录三。
4.总结
数据解析的内容到现在也已经介绍完毕。我介绍的只是常⽤的数据解析⽅法,当然还有很多数据解析的⽅法,⽐如Bautifulsoup、PyQuery……但是我上⾯介绍的这些已经完全⾜够了。每⼀种都能够获取想要的数据,只不过获取的⽅式有所不同。具体使⽤哪种⽅式取决于所要爬取的⽹页结构。这⾥需要注意的是我们在安装了parsel库之后就不需要另外再安装css以及xpath库了,在这⾥就可以直接构建selector对象并使⽤,还是⼗分⽅便的。如果⼤家对于爬⾍有需求或者是有疑惑可以联系我。下⼀次给⼤家介绍数据持久化的⽅式,也就是我们常说的将数据保存为xlsx、csv、txt……等的⼀些格式,⽽不单单是打印出来,以便我们后续对数据进⾏操作。
附录⼀:
import requests
import re
for page in range(1, 11):
print(f'----正在抓取第{page}页数据---')
response = (f'fabiaoqing/biaoqing/lists/page/{page}.html')
html_data =
# print(html_data)
# 数据解析
"""
<img class="ui image lazy" data-original="(.*?)"
"""
result_list = re.findall('<img class="ui image lazy" data-original="(.*?)"', html_data, re.S)
# print(result_list)
for result in result_list:
img_data = (result).content  # 请求到的图⽚数据
# 准备⽂件名
file_name = result.split('/')[-1]
with open('img\\' + file_name, mode='wb') as f:
f.write(img_data)
print('保存完成:', file_name)
附录⼆:
import parsel
import requests
for page in range(0, 226, 25):
print('-' * 100)
url = f'movie.douban/top250?start={page}&filter='
headers = {
'Host': 'movie.douban',
'Cookie': 'bid=0Zh2xEHDtYQ; dbcl2="244637883:MwqForzW8Xw"; ck=5JFU; push_doumail_num=0; '
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36',    }
# 2. 发送请求
response = (url=url, headers=headers)
html_data =
# ⼀定要对⽐数据,确认我们要的数据已经请求到了
selector = parsel.Selector(html_data)
lis = selector.css('.grid_view li')  # 所有li标签
for li in lis:
title = li.css('.title::text').get()
info = li.css('.bd p:nth-child(1)::text').getall()
score = li.css('.rating_num::text').get()
follow = li.css('.star span:nth-child(4)::text').get()
print(title, info, score, follow)
附录三:
import requests
import parsel
url = 'nba.hupu/stats/players/pts'
# 2. 发送⽹络请求
response = (url=url)
html_data =
# print(html_data)  # 通过数据对⽐确认了我想要的数据已经请求下来了
# 3.1 转换数据类型
selector = parsel.Selector(html_data)
trs = selector.xpath('//table[@class="players_table"]/tbody/tr')[1:]  # ⼆次提取for tr in trs:
rank = tr.xpath('./td[1]/text()').get()  # 排名
player = tr.xpath('./td[2]/a/text()').get()  # 球员
team = tr.xpath('./td[3]/a/text()').get()  # 球队
score = tr.xpath('./td[4]/text()').get()  # 得分
hit_shot = tr.xpath('./td[5]/text()').get()  # 命中-出⼿
hit_rate = tr.xpath('./td[6]/text()').get()  # 命中率
hit_three = tr.xpath('./td[7]/text()').get()  # 命中-三分
three_rate = tr.xpath('./td[8]/text()').get()  # 三分命中率
hit_penalty = tr.xpath('./td[9]/text()').get()  # 命中-罚球
penalty_rate = tr.xpath('./td[10]/text()').get()  # 罚球命中率
session = tr.xpath('./td[11]/text()').get()  # 场次
playing_time = tr.xpath('./td[12]/text()').get()  # 上场时间
print(rank, player, team, score, hit_shot, hit_rate,
hit_three, three_rate, hit_penalty, penalty_rate,
session, playing_time, sep=' | ')
# 4. 数据持久化