Ipidea丨Python解析HTML页面

作者:IPIDEA

2020-03-21 11:23:59

## Python解析HTML页面

---
一个完成的网络爬虫过程,除了想方设法获取正确的请求数据外,还需要对获取回的HTML页面进行相对应的解析,以方便我们提取所需要的信息。当然在提取内容相对单一的时候可以把整段HTML源码当成字符串,采用正则表达式直接提取,但当提取内容相对较多且情况复杂时,罗列正则表达式就会变得异常繁琐,更容易出错。
因此,对于HTML源码常常可以根据原有的节点,按照层次关系进行解析,利用XPath或CSS选择器,根据id和class等属性信息来定位具体的节点。Python中有许多相应的第三方解析库,常用的包括Beatiful Soup、lxml、pyqury,甚至于scrapy中的Selector等等。
本节我们主要介绍Python中使用XPath就页面进行解析的方法。

XPath其实是用来定位和检索XML路径的语言,但其同样也适用于HTML代码,熟练地使用XPath语法,可以帮助我们快速定位和提取相应的信息。

### lxml库的导入
这里我们使用lxml库中方法来对HTML进行XPath解析。
```python
from lxml import etree

text = """
<div>
<a class="collection" target="_blank" href="/a/b/sheying.html">
<img src="https://demo.io/images/1.jpg" />
<div class="name">摄影</div></a> 
<a class="collection" target="_blank" href="/a/b/dushu.html">
<img src="https://demo.io/images/2.jpg" />
<div class="name">读书</div></a>
<a class="collection" target="_blank" href="/a/b/shenghuo.html">
<img src="https://demo.io/images/3.jpg"  />
<div class="name">生活</div></a>
</div>
"""
html = etree.HTML(text)
```
此时正文内容已被转换成XPath对象,如果想查看原文本内容,需要进行类型转换:
```python
r = etree.tostring(html)
print(r.decode('utf-8'))
```
输出结果与上文并不完全一致,因为etree会自动修复补全HTML代码,自动添加了body和html节点,这点应该需要了解注意。

### XPath的使用
XPath规则
|标识|说明|
|:--:|:--:|
| // |从当前节点选取所有子孙节点|
| / |从当前节点选择下一级子节点|
| . |选取当前节点|
| .. |选取当前节点的父节点|
| @ | 选取属性 |
|nodename|选取此节点,包含所有子节点|

   
接下来我们将使用XPath规则选取html代码中的所有节点:
```python
result = html.xpath('//*')
print(result)
```
运行结果:
```bash
[<Element html at 0x25b5289a988>,
 <Element body at 0x25b52f19ec8>,
 <Element div at 0x25b52c3d5c8>,
 <Element a at 0x25b5287ea48>,
 <Element img at 0x25b5287eb08>,
 <Element div at 0x25b5287ec08>,
 <Element a at 0x25b52884248>,
 <Element img at 0x25b52884188>,
 <Element div at 0x25b52884888>,
 <Element a at 0x25b5287ec48>,
 <Element img at 0x25b52884b48>,
 <Element div at 0x25b52884a88>]
```
此时选择器会选取该段HTML中所有的节点,并生成Element对象,返回一个结果列表。

选择子节点
由于HTML文本通常层级明确,因此在结构简单,层级较少的情况下,我们可以通过层级关系直接选择部分子节点,如:
```python
result = html.xpath('.//div/a/div')
print(result)
```
运行结果:
```bash
[<Element div at 0x25b5287ec08>,
 <Element div at 0x25b52884888>,
 <Element div at 0x25b52884a88>]
```
这样我们选取了所有a节点下的div标签,同样我们也可以选择a节点下的img标签:
```python
result = html.xpath('.//div/a/img')
print(result)
```
执行结果:
```bash
[<Element img at 0x25b5287eb08>,
 <Element img at 0x25b52884188>,
 <Element img at 0x25b52884b48>]
```

选取标签
在某些特定情况下,我们可以直接选取标签来提取结果,但这种情形通常在标签明确的情况下。例如我们需要提取页面中所有的图片,就可以直接选取HTML中的所有img标签,但当页面中存在一些我们不需要的img时,就需要增加允许访问公开数据条件了。
```python
result = html.xpath('//img')
print(result)
```
运行结果:
```bash
[<Element img at 0x25b5287eb08>,
 <Element img at 0x25b52884188>,
 <Element img at 0x25b52884b48>]
```

根据条件选择特定标签
除了按照标签名称或者层级关系,也可以更加标签的属性来选择相应的节点或标签:
```python
result1 = html.xpath('//a[@class="collection"]/img')
print(result1)
result2 = html.xpath('//div[@class="name"]')
print(result2)
```
执行结果:
```bash
[<Element img at 0x25b5287eb08>, <Element img at 0x25b52884188>, <Element img at 0x25b52884b48>]
[<Element div at 0x25b5287ec08>, <Element div at 0x25b52884888>, <Element div at 0x25b52884a88>]
```


提取内容
当我们按照XPath规则选择到相应的标签,通常下一步的操作就是提取标签内的部分信息,如文本、标题或者链接等:
```python
result1 = html.xpath('//a/div/text()')
print(result1)
result2 = html.xpath('//a/@href')
print(result2)
result3 = html.xpath('//a/img/@src')
print(result3)
```
执行结果:
```bash
['摄影', '读书', '生活']
['/a/b/sheying.html', '/a/b/dushu.html', '/a/b/shenghuo.html']
['https://demo.io/images/1.jpg','https://demo.io/images/2.jpg','https://demo.io/images/3.jpg']
```


### 结语
本节我们简单介绍了用XPath选择器对HTML文本进行解析的方法,这些方法在Python网络爬虫中具有极为重要的作用,熟练使用XPath将有助于信息的提取。


支持全球240个国家地区,每日超9000万住宅动态IP资源,欢迎访问:www.ipidea.net。

*ipidea提供的服务必须在境外网络环境下使用

热门资讯