在re、bs4、xpath等解析库中,re库运行起来效率最高,但用起来太麻烦;XPath 使用较为方便,而且效率损失不大。
0 安装 XPath Helper 插件
在 edge 浏览器的“扩展”中,开启“开发者模式”和“允许来自其他应用商店的扩展”,将文件夹《chrome_Xpath_v2.0.2》拖入到“扩展”页面中即可完成安装。
本人设置键盘快捷方式为“Ctrl+Shift+C”,这样每次想用时就可以快速打开这玩意了,再按下“F12”查看代码,就可以开玩 XPath 了。这个插件是真的好用,强烈推荐安装。
1 XPath 语法
1.1 节点
表达式
描述
用法举例
用法举例说明
nodename
选取此节点下的所有节点
div
选取div下的所有标签
//
全局节点(可粗略理解为“绝对路径”)
//div
选取整个HTML页面的所有div标签
//nodename//
选取某个节点下的所有节点(包括子节点、子节点的子节点…)
//header//div
选取header标签下的所有div标签,不管是不是header标签的第一级节点
/
选取某个节点下的子节点(可粗略理解为“相对路径”)(只能一级)
//div/a
选取div标签下的a标签(而非整个页面的a标签)
@
选取带有某个属性(attr)的节点
//div[@class]
选取带有class属性的div标签
@
获取属性的内容
//div/span/@title
选取span标签的属性title的内容
@attr=str
选取带有某个属性(attr)为str的节点
//div[@class=“menv”]
选取带有class属性为menv的div标签
.
当前节点下
./span
当前节点下的span标签
1.2 谓语
表达式
描述
用法举例
用法举例说明
[n]
当选取有多个标签时,可以指定选取第n个标签(注意n从1开始)
//div[@class=“menv”][2]
选取第二个带有class属性为menv的div标签
[last()]
选取最后一个标签
//div[last()]
选取最后一个div标签
[last()-n]
选取倒数第n个标签
//div[last()-3]
选取倒数第三个div标签
[position()<n]
选取前n个标签
//div[position()<3]
选取前三个div标签
[element表达式条件]
元素值符合表达式条件的标签
//div[price<35.00]
选取div标签且price元素需小于35.00
2 lxml 库使用实例
lxml 库的作用:将 html 字符串进行解析,供 XPath 语法进行数据提取。
现在我们通过一个实例来初步认知 lxml 的用法,如下为一个 HTML 字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 text = \ """ <ul class="ullist" padding="1" spacing="1"> <li> <div id="top"> <span class="position" width="350">职位名称</span> <span>职位类别</span> <span>人数</span> <span>地点</span> <span>发布时间</span> </div> <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=33824&keywords=python&tid=87&lid=2218">python开发工程师</a> </span> <span>技术类</span> <span>2</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="odd"> <span class="l square"> <a target="_blank" href="position_detail.php?id=29938&keywords=python&tid=87&lid=2218">python后端</a> </span> <span>技术类</span> <span>2</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=31236&keywords=python&tid=87&lid=2218">高级Python开发工程师</a> </span> <span>技术类</span> <span>2</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="odd"> <span class="l square"> <a target="_blank" href="position_detail.php?id=31235&keywords=python&tid=87&lid=2218">python架构师</a> </span> <span>技术类</span> <span>1</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=34531&keywords=python&tid=87&lid=2218">Python数据开发工程师</a> </span> <span>技术类</span> <span>1</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="odd"> <span class="l square"> <a target="_blank" href="position_detail.php?id=34532&keywords=python&tid=87&lid=2218">高级图像算法研发工程师</a> </span> <span>技术类</span> <span>1</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=31648&keywords=python&tid=87&lid=2218">高级AI开发工程师</a> </span> <span>技术类</span> <span>4</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="odd"> <span class="l square"> <a target="_blank" href="position_detail.php?id=32218&keywords=python&tid=87&lid=2218">后台开发工程师</a> </span> <span>技术类</span> <span>1</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=32217&keywords=python&tid=87&lid=2218">Python开发(自动化运维方向)</a> </span> <span>技术类</span> <span>1</span> <span>上海</span> <span>2018-10-23</span> </div> <div id="odd"> <span class="l square"> <a target="_blank" href="position_detail.php?id=34511&keywords=python&tid=87&lid=2218">Python数据挖掘讲师 </a> </span> <span>技术类</span> <span>1</span> <span>上海</span> <span>2018-10-23</span> </div> </li> </ul> """
2.1 解析字符串为 HTML
这一步的操作是将字符串转化为可识别的 HTML,并且还会进行“查缺补漏”,修复不规范标签。
1 2 3 4 5 6 from lxml import etree''' 0. 解析字符串为 HTML ''' html = etree.HTML(text)
2.2 获取 div 标签
XPath 表达式://div
1 2 3 4 5 6 7 8 9 10 ''' 1. 获取 div 标签 ''' div1 = html.xpath('//div' ) for div in div1: d = etree.tostring(div, encoding='utf-8' ).decode('utf-8' ) print (d) print ('*' * 50 )
注意 1:div1 是一个列表,因此需要使用 for 对其进行访问遍历。
注意 2:若转化字符串和解析 HTML 时不用 utf8,则默认为 byte 流数据。
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <div id="top"> <span class="position" width="350">职位名称</span> <span>职位类别</span> <span>人数</span> <span>地点</span> <span>发布时间</span> </div> ************************************************** <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=33824&keywords=python&tid=87&lid=2218">python开发工程师</a> </span> <span>技术类</span> <span>2</span> <span>上海</span> <span>2018-10-23</span> </div> ************************************************** <div id="odd"> <span class="l square"> <a target="_blank" href="position_detail.php?id=29938&keywords=python&tid=87&lid=2218">python后端</a> </span> <span>技术类</span> <span>2</span> <span>上海</span> <span>2018-10-23</span> </div> ************************************************** (后面结果省略)
2.3 获取某个指定的 div 标签
假设我们想要获取第 1 个 div 标签,那么 XPath 表达式://div[1]
1 2 3 4 5 6 7 ''' 2. 获取某个指定的 div 标签 ''' div2 = html.xpath('//div[1]' )[0 ] DIV2 = etree.tostring(div2, encoding='utf-8' ).decode('utf-8' ) print (DIV2)
注意:div2 依然是一个列表,而且是只有一个元素的列表,存放了第一个 div 标签。
输出结果:
1 2 3 4 5 6 7 <div id="top"> <span class="position" width="350">职位名称</span> <span>职位类别</span> <span>人数</span> <span>地点</span> <span>发布时间</span> </div>
2.4 获取属性为 id=‘even’ 的 div 标签
XPath 表达式://div[@id=“even”]
1 2 3 4 5 6 7 8 9 10 ''' 3. 获取属性为 id='even' 的 div 标签 ''' div3 = html.xpath('//div[@id="even"]' ) for div in div3: d = etree.tostring(div, encoding='utf-8' ).decode('utf-8' ) print (d) print ('*' * 50 )
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=33824&keywords=python&tid=87&lid=2218">python开发工程师</a> </span> <span>技术类</span> <span>2</span> <span>上海</span> <span>2018-10-23</span> </div> ************************************************** <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=31236&keywords=python&tid=87&lid=2218">高级Python开发工程师</a> </span> <span>技术类</span> <span>2</span> <span>上海</span> <span>2018-10-23</span> </div> ************************************************** <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=34531&keywords=python&tid=87&lid=2218">Python数据开发工程师</a> </span> <span>技术类</span> <span>1</span> <span>上海</span> <span>2018-10-23</span> </div> ************************************************** <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=31648&keywords=python&tid=87&lid=2218">高级AI开发工程师</a> </span> <span>技术类</span> <span>4</span> <span>上海</span> <span>2018-10-23</span> </div> ************************************************** <div id="even"> <span class="l square"> <a target="_blank" href="position_detail.php?id=32217&keywords=python&tid=87&lid=2218">Python开发(自动化运维方向)</a> </span> <span>技术类</span> <span>1</span> <span>上海</span> <span>2018-10-23</span> </div> **************************************************
2.5 获取标签下的属性值
2.5.1 初步想法
XPath 表达式://div/@id 和 //a/@href
1 2 3 4 5 6 7 8 9 10 11 ''' 4. 获取标签下的属性值 ''' div4 = html.xpath('//div/@id' ) print (div4)hrefs = html.xpath('//a/@href' ) print (hrefs)
输出结果:
1 2 ['top', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd'] ['position_detail.php?id=33824&keywords=python&tid=87&lid=2218', 'position_detail.php?id=29938&keywords=python&tid=87&lid=2218', 'position_detail.php?id=31236&keywords=python&tid=87&lid=2218', 'position_detail.php?id=31235&keywords=python&tid=87&lid=2218', 'position_detail.php?id=34531&keywords=python&tid=87&lid=2218', 'position_detail.php?id=34532&keywords=python&tid=87&lid=2218', 'position_detail.php?id=31648&keywords=python&tid=87&lid=2218', 'position_detail.php?id=32218&keywords=python&tid=87&lid=2218', 'position_detail.php?id=32217&keywords=python&tid=87&lid=2218', 'position_detail.php?id=34511&keywords=python&tid=87&lid=2218']
2.5.2 改进程序
很多时候,在获取属性时,我们不想要这样一个长长的列表(因为处理起来有点麻烦),如果我们需要获取一个 url 字符串,那该怎么办呢?
观察 HTML,发现 a 标签都在 div 标签里。我们可以先获取 div 标签(这样就会得到一个 div 列表),遍历这个列表,再在里面获取 a 标签,这样就可以分离出每一个 url 了。
先选取 div 标签://div(得到一个许多元素的列表)
然后在以上基础选取 a 标签:.//a/@href(得到多个元素只有一个的列表)
注意:.表示上一个路径,意思是在 div
标签下进行全局选取。如果直接写成//a/@href,意思是在整个页面下进行全局选取 a 标签。
1 2 3 4 5 div4 = html.xpath("//div" )[1 :] for div in div4: url = div.xpath(".//a/@href" ) print (url)
输出结果:
1 2 3 4 5 6 7 8 9 10 ['position_detail.php?id=33824&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=29938&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=31236&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=31235&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=34531&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=34532&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=31648&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=32218&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=32217&keywords=python&tid=87&lid=2218'] ['position_detail.php?id=34511&keywords=python&tid=87&lid=2218']
这时我们得到的是许多列表,但是每个列表只有一个元素(字符串),处理起来方便多了。所以可以继续改进,url 列表获取 0 号元素,直接得到字符串:
1 2 3 4 5 div4 = html.xpath("//div" )[1 :] for div in div4: url = div.xpath(".//a/@href" )[0 ] print (url)
输出结果:
1 2 3 4 5 6 7 8 9 10 position_detail.php?id=33824&keywords=python&tid=87&lid=2218 position_detail.php?id=29938&keywords=python&tid=87&lid=2218 position_detail.php?id=31236&keywords=python&tid=87&lid=2218 position_detail.php?id=31235&keywords=python&tid=87&lid=2218 position_detail.php?id=34531&keywords=python&tid=87&lid=2218 position_detail.php?id=34532&keywords=python&tid=87&lid=2218 position_detail.php?id=31648&keywords=python&tid=87&lid=2218 position_detail.php?id=32218&keywords=python&tid=87&lid=2218 position_detail.php?id=32217&keywords=python&tid=87&lid=2218 position_detail.php?id=34511&keywords=python&tid=87&lid=2218
2.6 获取标签下的文本信息
假设我们想要获取 a 标签下的文本信息,那么:
先选取 div 标签://div(得到一个许多元素的列表)
然后在以上基础选取 a 标签的文本信息:.//a/text()(得到多个元素只有一个的列表)
1 2 3 4 5 6 7 8 ''' 5. 获取标签下的文本 ''' div5 = html.xpath("//div" )[1 :] for div in div5: work = div.xpath(".//a/text()" )[0 ] print (work)
输出结果:
1 2 3 4 5 6 7 8 9 10 python开发工程师 python后端 高级Python开发工程师 python架构师 Python数据开发工程师 高级图像算法研发工程师 高级AI开发工程师 后台开发工程师 Python开发(自动化运维方向) Python数据挖掘讲师
写在后面
搞了一晚上和一个白天,因为使用 PyCharm 调用 lxml 库时输出的结果完全不符合预期,今天重装了一次 lxml 库后居然恢复正常了,一直没有搞懂是怎么回事…
暂时就写这么多吧。
---EOF---