python小课堂32 - 初识原生爬虫(二)
python小课堂32
初识原生爬虫(二)
本篇阅读时间约为 6 分钟。
1
前言
为期紧张的两天线下课程结束了....跑上来继续完成前面爬虫系列!上章介绍了本次爬虫案例的需求,本节完成上次 TODO LIST 的后半部分代码编写以及介绍。本篇为代码讲解,没有耐心的童鞋看大概会非常枯燥吧,所以配了一首歌,静静的听,适合学习。
回顾上篇关联性文章如下:
PS:本期爬虫案例并不是最完善的爬虫,仅为了将爬虫的原理基础介绍清楚。要清楚,爬虫具有时效性,由于现在各大网站都有相关的反爬机制,所以也许现在写的爬虫代码此时适用,但过些时日就可能失效了,这点需要注意。本章仅供学习参考,请在遵守网络法律前提下进行相关操作。
2
爬虫代码架构
有了需求以后,第一件事要干的就是搭出代码的整体架构,借此机会,我们可以将面向对象章节介绍的知识点串联到本章来使用,若需回顾可以点击如下查看:
经需求设计,已知步骤有:
1. 模拟请求网页,拿到返回的网页源代码
2. 解析返回的源代码,对想要的信息进行节点的提取
3. 有上两步骤,最终运行代码
具体架构如下:
class SpiderPandas(object):
""" 类:原生爬虫 - 爬取 熊猫王者荣耀 直播
目标:直播标题、主播网名、热度
"""
def __crawl_html(self):
""" 请求网页源码,私有方法 """
pass
def __analysis_node(self):
""" 分析网页返回的节点,私有方法 """
pass
def run(self):
""" 运行方法 """
pass
设计一个爬虫类,其中模拟请求和解析网页节点的方法设置为私有方法,类的内部使用即可,类外部需要调用的是公开的 run 运行方法。
3
模拟请求
所谓的原生爬虫,直接使用 python 自带的库完成对网页进行模拟请求,而此处的自带库就是 urllib 了!简单的介绍一下,模拟请求网页只需要使用到 urllib 下的 request 方法即可,名如起义,就是请求的意思。本处不会过多介绍其使用方法,重点是一步步的思路,具体可以去官方文档网站查看:
https://docs.python.org/3/library/urllib.html
有了使用方法后,我们来尝试写一下代码,变成如下:
from urllib import request
class SpiderPandas(object):
""" 类:原生爬虫 - 爬取 熊猫王者荣耀 直播
目标:直播标题、主播网名、热度
"""
# 请求网页的url
url = 'https://www.panda.tv/cate/kingglory'
def __crawl_html(self):
""" 请求网页源码,私有方法 """
r = request.urlopen(SpiderPandas.url)
html_content = r.read()
print(type(html_content))
print(html_content)
if __name__ == '__main__':
spiderPandas = SpiderPandas()
spiderPandas.run()
首先先把 request 导入,然后定义类变量 url ,对其发出模拟请求,调用 request 的 urlopen 方法,传入 url 即可。使用 r 变量接受,再次调用 r 的read 方法即可得到网页源代码内容。关于
if __name__ == '__main__':
的用法,大家可以自行网上查阅资料,通俗的解释就是可以将其看做入口函数,代码会先从此处进入执行。
可以看下上述代码的最终结果:
返回结果是字节类型的,将之打印输出,可以看到后续中文是字节码,所以还需要将之转化为字符串才可以。如下:
from urllib import request
class SpiderPandas(object):
""" 类:原生爬虫 - 爬取 熊猫王者荣耀 直播
目标:直播标题、主播网名、热度
"""
# 请求网页的url
url = 'https://www.panda.tv/cate/kingglory'
def __crawl_html(self):
""" 请求网页源码,私有方法 """
r = request.urlopen(SpiderPandas.url)
html_content = r.read()
html_content = str(html_content,encoding='utf-8')
print(type(html_content))
print(html_content)
if __name__ == '__main__':
spiderPandas = SpiderPandas()
spiderPandas.run()
有了以上代码,模拟网页请求并且获取到其源代码便完成了。如果在 pycharm 不好观察节点信息,可以将之复制到在线网页格式化html的网页工具中,先格式化一下,变成漂亮的代码后再复制到文本中查看即可。
4
分析 html 信息节点
再来回顾分析一下我们要爬取的信息节点,打开 F12 ,通过观察可以发现,需要的信息都在这一个大的 div 标签下,这样一来,就非常省事儿了!
粘出来格式化下,看得更清楚:
<div class="video-info">
<span class="video-title" title="五排开车">五排开车</span>
<span class="video-nickname" title="简单点丶无双"> <i class="icon-hostlevel icon-hostlevel-10" data-level="10"></i> 简单点丶无双 </span>
<span class="video-number"><i class="ricon ricon-eye"></i>5921</span>
<span class="video-station-info"> <i class="ricon ricon-fleet"></i> <i class="video-station-num">3人</i> </span>
</div>
用思维导图画出来,其一是整体流程,其二是具体分析:
还记得很早之前的正则表达式就说过,如果会用正则的话,处理文本信息是非常容易并且省力的!正则相关内容回顾:
1. 正则匹配根节点 video - info
按照思维导图的步骤2进行细分,先把根节点整段内容匹配出来,代码如下:
import re
from urllib import request
class SpiderPandas(object):
""" 类:原生爬虫 - 爬取 熊猫王者荣耀 直播
目标:直播标题、主播网名、热度
"""
# 请求网页的url
url = 'https://www.panda.tv/cate/kingglory'
root_node_pattern = r'<div class="video-info">[\s\S]*?</div>'
def __crawl_html(self):
""" 请求网页源码,私有方法 """
r = request.urlopen(SpiderPandas.url)
html_content = r.read()
html_content = str(html_content, encoding='utf-8')
return html_content
def __analysis_node(self, html):
""" 分析网页返回的节点,私有方法 """
video_info_lists = re.findall(SpiderPandas.root_node_pattern, html)
print(video_info_lists)
def run(self):
""" 运行方法 """
html = self.__crawl_html()
self.__analysis_node(html)
if __name__ == '__main__':
spiderPandas = SpiderPandas()
spiderPandas.run()
说下思路,请求网页的源码私有方法,可以对其 return ,使得解析节点的私有方法调用。重要的是写出匹配 video-info 的根节点正则表达式,也就是 root_node_pattern 。使用 re.findall 进行全局匹配,结果如下:
列表呈现的各节点信息。但是这样会发现一个问题,匹配到的内容是包含边界原字符(也就是div class = "video-inof....")的。所以可以改变正则匹配,使用分组即可去除!
root_node_pattern = r'<div class="video-info">([\s\S]*?)</div>'
2. 正则匹配根节点下的细节信息
# 房间名称正则
title_node_pattern = r'<span class="video-title" title="([\s\S]*?)">'
# 主播称号正则
nickname_node_pattern = r'<span class="video-nickname" title="([\s\S]*?)">'
# 房间热度正则
number_node_pattern = r'ricon-eye"></i>([\s\S]*?)</span>'
def __analysis_node(self, html):
""" 分析网页返回的节点,私有方法 """
video_info_lists = re.findall(SpiderPandas.root_node_pattern, html)
for video_info in video_info_lists:
title = re.findall(SpiderPandas.title_node_pattern, video_info)[0]
nickname = re.findall(SpiderPandas.nickname_node_pattern, video_info)[0]
number = re.findall(SpiderPandas.number_node_pattern, video_info)[0]
print(f'房间名称:{title},主播名称:{nickname},房间热度:{number} \n')
类似根节点的处理方式一样,找规律,正则具体内容一样,在私有的分析节点方法中直接 for 循环拿出每个大 div 来,在对每个 video-info 下的三类进行正则匹配,最后输出打印:
5
总结
可以看到,上面的所有思路已经将小爬虫最主要的功能实现了,但是对于有些细节实现并不完美,后续还会有一章讲解哪些地方应该进行优化,哪些地方是代码的缺陷。
至此完!
爬虫之前必会的浏览器开发者工具
数据分析培训的一天
长按关注
公众号名称:咪哥杂谈
一个咪咪怪的公众号
长按二维码关注哦!