查看原文
其他

python小课堂32 - 初识原生爬虫(二)

咪咪怪 咪哥杂谈 2019-10-30
咪哥杂谈

python小课堂32

初识原生爬虫(二)


本篇阅读时间约为 6 分钟。


1

前言


为期紧张的两天线下课程结束了....跑上来继续完成前面爬虫系列!上章介绍了本次爬虫案例的需求,本节完成上次 TODO LIST 的后半部分代码编写以及介绍。本篇为代码讲解,没有耐心的童鞋看大概会非常枯燥吧,所以配了一首歌,静静的听,适合学习。


回顾上篇关联性文章如下:


python小课堂31 - 初识原生爬虫


PS:本期爬虫案例并不是最完善的爬虫,仅为了将爬虫的原理基础介绍清楚。要清楚,爬虫具有时效性,由于现在各大网站都有相关的反爬机制,所以也许现在写的爬虫代码此时适用,但过些时日就可能失效了,这点需要注意。本章仅供学习参考,请在遵守网络法律前提下进行相关操作。


2

爬虫代码架构


有了需求以后,第一件事要干的就是搭出代码的整体架构,借此机会,我们可以将面向对象章节介绍的知识点串联到本章来使用,若需回顾可以点击如下查看:


python小课堂18 - 面向对象篇(一)

python小课堂19 - 面向对象篇(二)

python小课堂21 - 面向对象(三)

python小课堂22 - 面向对象(四)


经需求设计,已知步骤有:

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>


用思维导图画出来,其一是整体流程,其二是具体分析:




还记得很早之前的正则表达式就说过,如果会用正则的话,处理文本信息是非常容易并且省力的!正则相关内容回顾:


python小课堂23 - 正则表达式(一)

python小课堂24 - 正则表达式(二)


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

总结


可以看到,上面的所有思路已经将小爬虫最主要的功能实现了,但是对于有些细节实现并不完美,后续还会有一章讲解哪些地方应该进行优化,哪些地方是代码的缺陷。



至此完!




▼往期精彩回顾▼初识原生爬虫(一)
爬虫之前必会的浏览器开发者工具
数据分析培训的一天


长按关注

公众号名称:咪哥杂谈

一个咪咪怪的公众号

长按二维码关注哦!



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存