从零开始,学会Python爬虫不再难!!! -- (2)承接:解析网页,抓取标签 丨蓄力计划
发布日期:2021-06-30 19:48:02 浏览次数:3 分类:技术文章

本文共 7454 字,大约阅读时间需要 24 分钟。

在这里插入图片描述

文章目录

上图已魔法反爬,哈哈哈,想爬就爬呗,不拦着


认识HTML源代码

说到解析网页,那么我们是不是要自己先了解一下这些个网页呢?

来看一下这个网页:

在这里插入图片描述

解析网页

来,我们就拿这个网页来研究一下它的构造,后面其他的网页都是共通的。

首先可以看到在网页的左侧,输入框有颜色。在网页的右侧,也有一段有颜色的代码,这是怎么肥四呢?

这叫做标记,或者叫搜索,或者叫映射,爱怎么叫怎么叫,咱只需要知道左右两个有颜色的地方是一一对应的。

那,要怎么根据页面元素去搜索它对应的代码块儿呢,其实不难哈。

在这里插入图片描述

先点击我圈出来的地方,再到网页上点击对应的元素即可。

我们再把目光聚焦在右侧的代码上,可以看到很多的三角形。稍微思索一下,就知道那些三角形是上下级的关系吧。

在这里插入图片描述

这些三角形是可以伸缩的。我们把每个三角形以及它包含的所有内容叫做:标签。

(当然,有些没有三角形的也叫标签,比方说)
在这里插入图片描述

怎么看标签呢,以"<“为标签的起始,”>"为标签的结尾。

这时候就会有同级标签和上下级标签的区分了,我习惯把它们之间的关系称呼为:父标签、子标签、兄弟标签以及祖标签

这些概念在后面讲Xpath标签提取的时候会很重要,都长点记性哈。


认识Xpath

XPath 是一种将 XML 文档的层次结构描述为关系的方式。因为 HTML 是 由 XML 元素组成的,因此我们可以使用 XPath 从 HTML 文档中定位和选择元素。

要说从网页源码中提取出数据来,那方法其实不少的。比方说某些人动不动就上来一个正则表达式啊,本系列主干中不提正则表达式,最多作为“番外篇”加入。怎么简单怎么来嘛。

也有些人会用beautifulsoup,我初学的时候也是学这个库的,后来发现有诸多的不便性,于是果断放弃了。

其实也没多少不便,就是学完Xpath之后怎么看soup怎么不顺眼。

来看一下它们仨儿的性能对比哈:

抓取方法 性能 使用难度 安装难度
正则 困难 内置模块
beautifulsoup 简单 简单(纯Python)
lxml 简单 不难

可以看出beautiful为什么慢了吧。在pycharm下,没有太多的安装困难啦。


Xpath使用流程

看完Xpath的性能优势之后,我们来看一下Xpath是如何解析一个网页,并获取到我们所需要的数据的。

在这里插入图片描述

别急,我来解释一下这张图。

1、首先,导入Xpath支持的模块,位于lxml包里面的etree模块,如果用pycharm时出现“报错”,别管它,能运行的,历史遗留原因。2、其次,获取网页源码,这里需要使用content方法来对获取到的网页数据进行转换,不能使用text。3、接着,对转换出的数据进行编解码。不然会看到一堆的乱码。4、HTML方法,没什么好说的。5、xpath方法,这里需要传入参数为待提取标签的Xpath路径。关于这个路径,一会儿会讲。6、批量提取,关于这个批量提取,一会儿也会讲。7、没什么好说的了。

Xpath路径提取

在这里插入图片描述

打开谷歌浏览器,在标签上方,进行一次右击,点击那个“copy”,选择里面的“Copy Xpath”,没啥事儿的话就不要去“Copy Full Xpath”了。

这里我们统一使用谷歌浏览器。

这时候相对Xpath路径我们就拿到了。


Xpath基本语法节选

Xpath的语法太多了,但是我们一般用不到那么多,没必要死记硬背,我给你们挑一些常用的就好。

在这里插入图片描述

示例:

在这里插入图片描述

示例:

还有一个text()方法注意一下即可,没必要搞那么多的花里胡哨的。


Xpath函数封装

讲到这里Xpath部分也差不多了,我们来封装一下函数,并做一个小demo。

如果是要提取单个路径下的标签,采用以下方法即可:

def get_data(html_data,Xpath_path):    '''    这是一个从网页源数据中抓取所需数据的函数    :param html_data:网页源数据 (单条数据)    :param Xpath_path: Xpath寻址方法    :return: 存储结果的列表    '''        data = html_data.content    data = data.decode().replace("
", "") #删除数据中的注释 tree = etree.HTML(data) #创建element对象 el_list = tree.xpath(Xpath_path) return el_list

如果是要从多个Xpath中提取数据,可以采用以下方法:

def get_many_data(html_data,Xpath_path_list):    '''    通过多个Xpath对数据进行提取    :param html_data: 原始网页数据    :param Xpath_paths: Xpath寻址列表    :return: 二维列表,一种寻址数据一个列表    '''    el_data = []        data = html_data.content    data = data.decode().replace("
", "") tree = etree.HTML(data) for Xpath_path in Xpath_path_list: el_list = tree.xpath(Xpath_path) el_data.append(el_list) el_list = [] #安全起见就自己清理了吧 return el_data

至于要不要修修补补,就看个人喜好啦。


Xpath实操爬取小demo

我们来做一个小demo,获取

在这里插入图片描述

(图片更换过,不知道为啥就图片违规)

这里的热榜文本和网址,并一一配对吧。

首先,我们审查以下网页:

在这里插入图片描述

学的快的人看出两个线索,有经验的人看出三个线索:

在这里插入图片描述

看到网址和文本是应该的,不过我们要一次性全部拿下,就需要查看其它的几个标签所在位置,然后,找到我们所需要的所有标签的最小公共祖宗标签

在这里插入图片描述

将标签叠起来,我们很容易的发现它们都处在<ul>这个标签下。

那就有办法一次全部提取出来了,如果没想明白的话建议翻到上面Xpath基本语法节选部分再想明白。

先对第一个标签进行提取,发现文本路径为://*[@id="hotsearch-content-wrapper"]/li[1]/a/span[2]

而网址路径为://*[@id="hotsearch-content-wrapper"]/li[1]/a/@href

很显然,li[1]代表的是第一个标签,而下面五个标签分别对应li[2]、li[3]、以此类推,此处可以优化为 //li

而对于 li标签以下的部分,我们可以用简单粗暴的 全部提取//的方式提取文本吗?并不行,因为在li标签下有多类文本,而我们只要一种。

所以我们的Xpath路径这样写:

//*[@id="hotsearch-content-wrapper"]//li/a./span[2]/text() | ./@href

或者这样:

//*[@id="hotsearch-content-wrapper"]//li/a/span[2]/text() | //*[@id="hotsearch-content-wrapper"]//li/a/@href

一个是时间,一个是空间,自己选一个吧。

所以代码也就很快出来了啊:

import requests     #做爬虫比较常用的一个包import randomimport timefrom lxml import etreeurl = 'https://www.baidu.com/?tn=48021271_10_hao_pg'def get_html(url,header_list,sleep_time):    times = 3    try:        res = requests.get(url=url, headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}) if res.status_code >= 200 and res.status_code<300: time.sleep(sleep_time) return res else: return None except Exception as e: print(e) if times>0: print("机会次数:"+str(times)) get_html(url, header_list,sleep_time) else: print("无法爬取")def get_data(html_data, Xpath_path): ''' 这是一个从网页源数据中抓取所需数据的函数 :param html_data:网页源数据 (单条数据) :param Xpath_path: Xpath寻址方法 :return: 存储结果的列表 ''' data = html_data.content data = data.decode().replace("
", "") # 删除数据中的注释 tree = etree.HTML(data) # 创建element对象 el_list = tree.xpath(Xpath_path) return el_listres = get_html(url=url,header_list=header_list,sleep_time=2)#print(res.content)el_list = get_data(res,'//*[@id="hotsearch-content-wrapper"]//li/a')for el in el_list: e = el.xpath('./span[2]/text() | ./@href') print(e)

得到结果:

['https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E6%89%93%E5%AE%8C%E7%96%AB%E8%8B%97%E5%90%8E%E8%8B%A5%E5%8F%91%E7%83%A7%E4%B8%8D%E9%80%80%E7%AD%89%E8%A6%81%E6%8A%A5%E5%91%8A&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1', '打完疫苗后若发烧不退等要报告']['https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E8%BE%BD%E5%AE%81%E8%88%B0%E5%92%8C%E7%BE%8E%E5%9B%BD%E9%A9%B1%E9%80%90%E8%88%B0%E8%BF%91%E8%B7%9D%E7%A6%BB%E7%A2%B0%E9%9D%A2&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1', '辽宁舰和美国驱逐舰近距离碰面']['https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E5%93%88%E9%87%8C%E5%B0%86%E8%BF%94%E8%8B%B1%E5%8F%82%E5%8A%A0%E8%8F%B2%E5%88%A9%E6%99%AE%E4%BA%B2%E7%8E%8B%E8%91%AC%E7%A4%BC&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1', '哈里将返英参加菲利普亲王葬礼']['https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E7%BE%8E%E9%BB%91%E4%BA%BA%E5%86%9B%E5%AE%98%E9%81%AD%E7%99%BD%E4%BA%BA%E8%AD%A6%E5%AF%9F%E5%96%B7%E8%BE%A3%E6%A4%92%E6%B0%B4&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1', '美黑人军官遭白人警察喷辣椒水']['https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E5%8C%BB%E7%94%9F%E8%87%AA%E6%9B%9D%E6%94%B6%E5%9B%9E%E6%89%A350%E5%A4%9A%E4%B8%87+%E5%8D%AB%E5%81%A5%E5%A7%94%E8%B0%83%E6%9F%A5&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1', '医生自曝收回扣50多万 卫健委调查']['https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E8%82%AF%E5%BE%B7%E5%9F%BA%E8%AF%AF%E6%8A%8A%E6%B6%88%E6%AF%92%E6%B0%B4%E7%BB%99%E5%A5%B3%E5%AD%A9%E9%A5%AE%E7%94%A8&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1', '肯德基误把消毒水给女孩饮用']

注意看这个结果,排列的也是很有规律性的。


requests-html

requests-html和其他解析HTML库最大的不同点在于HTML解析库一般都是专用的,所以我们需要用另一个HTTP库先把网页下载下来,然后传给那些HTML解析库。而requests-html自带了这个功能,所以在爬取网页等方面非常方便。

有了上面的铺垫,下面这些应该是轻车熟路了,我就不多说,直接上实操。


requests-html获取网页源码

from requests_html import HTMLSessionsys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030')  # 改变标准输出的默认编码session = HTMLSession()r = session.get('https://www.baidu.com/?tn=48021271_10_hao_pg',headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"})# 查看页面内容print(r.html.html)print(r.html.links) # 获取所有链接print(r.html.text) # 获取所有文本print(r.html.absolute_links) # 获取全部绝对链接print(r.html.raw_html) # 返回二进制

抓取标签

这里抓取标签依旧是Xpath,不过就是把过程简化了,其实用我们上面封装好的函数也不比这个麻烦。

这里只讲Xpath,这需要另一个函数xpath的支持,它有4个参数如下:

- selector,要用的XPATH路径;- clean,布尔值,如果为真会忽略HTML中style和script标签造成的影响(原文是sanitize,大概这么理解);- first,布尔值,如果为真会返回第一个元素,否则会返回满足条件的元素列表;- _encoding,编码格式。
print(r.html.xpath("//div[@id='menu']", first=True).text)print(r.html.xpath("//div[@id='menu']/a"))print(r.html.xpath("//div[@class='content']/span/text()"))

如果仅仅是获取这些东西的话,我建议直接使用lxml,因为这个模块的底层也是封装了lxml、requests、beautifulsoup等模块包的。


今天先到这里啦,下一篇见啦。

(不要问我为什么不讲requests-html对JavaScript的支持,问就是目前没必要,后面有更简单的方法)


系列导读

这个系列是什么?

本系列会写一些什么内容,在开头那张思维导图里面写了个大概了,至于导图里面没有写出来的,就作为一些探索的内容吧。

我之前有写过一个Python爬虫自学系列,反响也还可以,不过那个系列里面的不少链接是另一个付费专栏里面的内容了,相对要阅读就有些困难。

这个系列是在原有知识点的基础上,加入一些新的知识点,重新写的一个系列。不出意外,这个系列将会是我在Python爬虫领域的最后一个教学系列。


本系列配套资源

这个系列是会有配套视频课的,将会发布在CSDN学院上,当然,如果还是喜欢看博文的朋友可以看我的这个系列。


系列适用人群

有Python基本语法基础的人,分支循环、函数、类、模块、异常处理等。

不喜欢枯燥乏味的填鸭式教育的朋友。

肯动手实操为最佳。


在这里插入图片描述

转载地址:https://lion-wu.blog.csdn.net/article/details/115572504 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:AttributeError: module ‘urllib‘ has no attribute ‘quote‘的解决办法
下一篇:从零开始,学会Python爬虫不再难!!! -- (1)开篇:初识爬虫,基础铺垫 丨蓄力计划

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月22日 04时20分27秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

pytorch训练cifar10数据集查看各个种类图片的准确率 2019-04-30
Python鼠标点击图片,获取点击点的像素坐标 2019-04-30
路径规划(一) —— 环境描述(Grid Map & Feature Map) & 全局路径规划(最优路径规划(Dijkstra&A*star) & 概率路径规划(PRM&RRT)) 2019-04-30
神经网络调参实战(四)—— 加深网络层次 & 批归一化 batch normalization 2019-04-30
数据挖掘与数据分析(三)—— 探索性数据分析EDA(多因子与复合分析) & 可视化(1)—— 假设检验(μ&卡方检验&方差检验(F检验))&相关系数(皮尔逊&斯皮尔曼) 2019-04-30
RRT算法(快速拓展随机树)的Python实现 2019-04-30
路径规划(二) —— 轨迹优化(样条法) & 局部规划(人工势能场法) & 智能路径规划(生物启发(蚁群&RVO) & 强化学习) 2019-04-30
D*算法 2019-04-30
强化学习(四) —— Actor-Critic演员评论家 & code 2019-04-30
RESTful API 2019-04-30
优化算法(四)——粒子群优化算法(PSO) 2019-04-30
数据挖掘与数据分析(三)—— 探索性数据分析EDA(多因子与复合分析) & 可视化(2)——回归分析(最小二乘法&决定系数&残差不相关)&主成分分析&奇异值分解 2019-04-30
数据在Oracle中的存储 2019-04-30
优化算法(五)—人工蜂群算法Artificial Bee Colony Algorithm(ABC) 2019-04-30
轨迹规划 trajectory planning 2019-04-30
AGV自动导引运输车 2019-04-30
Trie树(字典树) 2019-04-30
COMP7404 Machine Learing——Logistic Regression 2019-04-30
COMP7404 Machine Learing——Regularization(参数C) 2019-04-30
COMP7404 Machine Learing——KNN 2019-04-30