Python小实战——原生爬虫
前言:在网络无处不在的今天,大数据的分析与提取也逐渐发展了起来。现在我们使用Python来做一个原生爬虫的小案例——爬取斗鱼直播平台分区下推荐视频播放量的排名,通过这个案例可以回顾前面所学的正则表达式等知识。
原生爬虫步骤:
1.模拟请求
2.用标签定位并提取数据(重点是正则表达式的编写)
3.数据精炼
4.业务处理
一. 模拟请求
-
建立Spider类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17from urllib import request
class Spider:
url = "https://www.douyu.com/g_LOL"
def __fetch_content(self):
r = request.urlopen(Spider.url)
htmls = r.read()
# 此处断点调试
def go(self):
self.__fetch_content()
spider = Spider()
spider.go()调试结果
可以看出,需要对htmls进行转码:
1
htmls = str(htmls,encoding='utf-8')
再次调试后报错:
网上查阅资料后发现,是因为:
以"b’\x1f\x8b\x08"开头的 ,说明它是gzip压缩过的数据,这也是报错的原因,所以我们需要对我们接收的字节码进行一个解码操作。
修改代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23from urllib import request
from io import BytesIO
import gzip
class Spider:
# 需要爬虫的URL
url = "https://www.douyu.com/g_LOL"
def __fetch_content(self):
r = request.urlopen(Spider.url)
# 获取HTML字节码
htmls = r.read()
buff = BytesIO(htmls)
f = gzip.GzipFile(fileobj=buff)
result = f.read().decode("utf-8") # 解码
def go(self):
self.__fetch_content()
spider = Spider()
spider.go()调试结果:
可以看到,已经爬取到了网页的HTML数据
-
上面部分可能会遇到的错误与解决方法
urllib.error.URLError: urlopen error [SSL: CERTIFICATE_VERIFY_FAILED]
1
2
3
4# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
二. 定位数据与提取、业务处理
-
第一步:观察游览器内HTML数据,尽可能选择闭合标签
如上图所示,我定位到了包含了主播名字、播放量的数据的div标签
-
第二步:编写正则表达式,抽取div标签
1
2root_pattern = '<div class="DyListCover-info">[\s\S]*?</div>'
# 使用re.findall方法匹配取得一个列表后,打印其中一个元素验证是否获取成功
可以看到,我们成功获取了主播"芜湖大司马"的一个视频播放量"224.9万",但还需要精确提取
-
第三步:在div标签中抽取数据
1
2# 在正则表达式中加入组()标签,即可取出中间内容
root_pattern = '<div class="DyListCover-info">([\s\S]*?)</div>'写名字、播放量的正则表达式(根据有规律的标签定位)
1
2name_pattern = '<use xlink:href="#icon-user_c95acf8"></use></svg>([\s\S]*?)</h2>'
number_pattern = '</use></svg>([\s\S]*?)</span><h2 class="DyListCover-user is-template">'然后调用函数进行匹配
1
2
3
4
5
6
7
8
9
10def __analysis(self, htmls):
root_html = re.findall(Spider.root_pattern, htmls)
anchors = []
for html in root_html:
name = re.findall(Spider.name_pattern, html)
number = re.findall(Spider.number_pattern, html)
if name != []:
anchor = {"name": name, "number": number}
anchors.append(anchor)
return anchors匹配并打印anchors结果如下
可以看到,我们已经成功抓取出这部分数据了
-
第四步:数据精炼
1
2
3
4
5
6def __refine(self, anchors):
l = lambda anchor: {
"name": anchor["name"][0].strip(), # strip()为python内置函数
"number": anchor["number"][0], # 用于去除字符串前后空格
}
return map(l, anchors) -
第五步:业务处理(排序)
1
2
3
4
5
6
7
8
9
10
11
12
13
14def __sort(self, anchors):
anchors = sorted(
anchors, key=self.__sort_seed, reverse=True
) # 第二个参数为key,指定比较大小的元素,第三个参数reverse可调整顺序或倒序排序
return anchors
def __sort_seed(self, anchor):
r = re.findall("\d*", anchor["number"])
number = float(r[0])
if "万" in anchor["number"]: # 将万转换为10000
number *= 10000
return number -
第六步:打印数据
1
2
3
4
5
6
7
8
9
10
11
12def __show(self, anchors):
# for anchor in anchors:
# print(anchor['name'] + "-----" + anchor['number'])
for rank in range(0, len(anchors)):
print(
"rank"
+ str(rank + 1)
+ ": "
+ anchors[rank]["name"]
+ " "
+ anchors[rank]["number"]
)结果:
三. 总结
以上就是简单的使用Python原生爬虫的一个小案例,虽然成功爬取,但是代码复用性较差(比如只能爬取斗鱼某个区的视频播放量,如果更换其他直播平台要重写正则表达式),可以考虑使用框架(如Scrapy)。
除此之外,由于网站的不断更新迭代,前面所写的正则表达式可能失效。
下面是总体代码,更新时间:2022-10
1 | from urllib import request |