一、工欲善其事,必先利其器:
鉴于很多新手朋友学习爬虫都绕不开BeautifulSoup(以下简称BS模块)与lxml模块。这些模块作为爬虫解析网页的杀手级武器,强大的同时也带来了一些复杂甚至是冗杂。很多新手朋友看到文档时都头痛不已,不知该从何下手,那么多的属性,那么多的对象与方法,该用哪一个呢?其实常用的来说就那几个。关于BeautifulSoup与lxml模块,我们一定是选择lxml模块的,因为它简洁快速,能在速度上碾压正则与BS模块,这对于弥补python天生作为一个脚本语言在速度上的劣势就显得十分的重要。下面列举一下解析对比表:
二、万事开头难(安装lxml):
看了上面的表格,相信你对lxml与BS模块一定有了基本的了解,很多朋友在尝试lxml模块的时候,第一步就被难住了!怎么顺利安装上lxml模块呢?Linux下安装还好说,一句 pip3 install lxml即可搞定,但是作为日常开发测试用的Windows就有点麻烦,因为需要安装C语言库。经过百度发现,很多人都在教我们如何用VS来编译,这些zz,肯定是忘记了“人生苦短,我用python”。其实安装lxml很简单:
安装wheel模块:
执行pip install wheel 即可,如果速度较慢可以执行pip install -i https://pypi.tuna.tsinghua.edu.cn/simple wheel 使用清华源速度较快。
安装lxml模块:
下载并安装lxml模块的whl文件。在这之前请先查看python的版本与位数:
从:Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32可以看到我这条电脑的python本文为3.7.4,是64位版本。
然后打开https://www.lfd.uci.edu/~gohlke/pythonlibs/直接按Ctrl+F 键入lxml 然后敲击回车定位到lxml所在位置。
下图中,红色框表示模块名字,lxml蓝色框表示版本,最新为4.5。粉色框也是最重要的要和你的python版本与位数相匹配,比如我的是64位python3.7,就应该选择并下载cp37 win_amd64.whl `文件:
最后一步,安装:
打开cmd,切换到下载的whl文件所在目录
执行pip install 你的whl文件名
例如pip install lxml-4.5.0-cp37-cp37m-win_amd64.whl
三、xpath定天下:
啰嗦了那么多,到这里就可以开始正式使用该模块了。我们在编写爬虫的过程中,无非就解析文本、链接等内容。
下面以B站排行榜为例子讲解具体抓取方法:
案例1 抓取排行榜视频标题以及视频连接
打开https://www.bilibili.com/ranking 按下F12 点击榜一标题,可以看到:
在这一行中标题被a标签包含,所指向的网址在href属性中。
往上看,是包含在 属性class等于info的div标签中,再上层是content,再上层是rank-item,也就是说排行中每一个视频的所有信息都存放在 rank-item这个大标签中。ok,开始用lxml解析。
分析完成以后开始码代码:
import requests
from lxml import etree #导入lxml.etree
#伪造一个请求头
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'}
#发出get请求,得到网页html“源码”
res = requests.get("https://www.bilibili.com/ranking", headers = headers)
#传入网页html“源码”,得到一个 etree.Element对象
html = etree.HTML(res.text)
#上述对象进行解析
info = html.xpath("//div[@class='info']/a")
'''
说明:
1.双斜杠//表示从任意位置开始匹配。
2.div[@class='info'] 表示匹配一个属性class=info的div标签。
3.单斜杠在这里表示“下面”的意思,也就是下面的a标签。
4.需要注意的是info两边加的是单引号,而双引号会报错。
总结:
在上面的分析中,我们知道 每条视频的标题和链接都在一个info div标签中,所以这句的意思就是匹配所有满足条件的属性class=info的div标签下面的a标签的内容
'''
print(info)
得到一堆对象:
继续码代码,得到地址和标题:
#遍历info,遍历的每一个item中都是一个属性class=info的div标签的内容
for i in info:
print(i.get('href')) #get一下a标签中 属性href的值,也就是视频连接
print(i.text) #得到a标签所包含的内容
怎么样?是不是非常的简单呢?
下面介绍一下上面用到的xpath常用语法:
路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
还可以使用*作为通配符,
路径表达式 结果
/bookstore/* 选取 bookstore 元素的所有子元素。
远远不止这些,可以参考w3c school xpath详细教程。
有了xpath你就可以精准定位每一个元素,还可以定位之后再次用xpath定位。
案例2 得到每个视频的播放量与弹幕数:
首先审查元素,分析目标html结构。我们可以发现,在属性class=content的div标签下面的属性class=info的div标签的下面的属性class=detail的div标签。下面的第一个span标签中有播放量信息,第二个span标签中有我们想要的弹幕数。那么,码代码吧!
bofang_text = html.xpath("//div[@class='detail']/span[1]/text()")
danmu_text = html.xpath("//div[@class='detail']/span[2]/text()")
print(bofang_text, danmu_text)
得到如下结果:
有点乱,我们还可以这样写:
bd_text = html.xpath("//div[@class='detail']")
for i in bd_text:
#二次xpath,获取第一个span标签包含的文本数据,播放量, 第二个是弹幕数
print(i.xpath("span[1]/text()"),i.xpath("span[2]/text()"))
这样分别得到了,播放量和弹幕数。
以上是对lxml和xpath的简单介绍。实际上xpath的语法是非常容易理解,并且性能也是非常不错的。一般都是我开发的首选。
更多干货内容,欢迎关注公众号:知了python