在上一课中我们讲到了使用Python获取网络资源,如果我们获取到一个或多个页面,需要从页面中提取出指定的信息,首先得掌握解析HTML页面的技术。上一课中我们把整个HTML页面当成一个字符串,使用正则表达式的捕获组提取出了需要的内容。但是,写出一个正确的正则表达式经常也是一件让人头疼的事情。为此,我们可以先了解HTML页面的结构,在此基础上就可以掌握其他的解析HTML页面的方法。
HTML页面的结构
我们在浏览器中打开任意一个网站,然后通过鼠标右键菜单,选择“显示网页源代码”菜单项,就可以看到网页对应的HTML代码。
代码的第1行是文档类型声明,第2行的<html>
标签是整个页面根标签的开始标签,最后一行是根标签的结束标签</html>
。<html>
标签下面有两个子标签<head>
和<body>
,放在<body>
标签下的内容会显示在浏览器窗口中,这部分内容是网页的主体;放在<head>
标签下的内容不会显示在浏览器窗口中,但是却包含了页面重要的元信息,通常称之为网页的头部。HTML页面大致的代码结构如下所示。
<!doctype html>
<html>
<head>
<!-- 页面的元信息,如字符编码、标题、关键字、媒体查询等 -->
</head>
<body>
<!-- 页面的主体,显示在浏览器窗口中的内容 -->
</body>
</html>
标签、层叠样式表(CSS)、JavaScript是构成HTML页面的三要素,其中标签用来承载页面要显示的内容,CSS负责对页面的渲染,而JavaScript用来控制页面的交互式行为。对HTML页面的解析可以使用一种名为XPath的语法,根据HTML标签的层次结构提取标签中的内容或标签属性;除此之外,也可以使用CSS选择器来定位页面元素,如果不清楚什么是CSS选择器,可以移步到我的《Web前端概述》一文进行了解。
XPath解析
XPath是在XML(eXtensible Markup Language)文档中查找信息的一种语法,XML跟HTML类似也是一种用标签承载数据的标签语言,不同之处在于XML的标签是可扩展的,可以自定义的,而且XML对语法有更严格的要求。XPath使用路径表达式来选取XML文档中的节点或者节点集,这里所说的节点包括元素、属性、文本、命名空间、处理指令、注释、根节点等。下面我们通过一个例子来说明如何使用XPath对页面进行解析。
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
对于上面的XML文件,我们可以用如下所示的XPath语法获取文档中的节点。
XPath还支持通配符用法,如下所示。
如果要选取多个节点,可以使用如下所示的方法。
说明:上面的例子来自于“菜鸟教程”网站上的XPath教程,有兴趣的读者可以自行阅读原文。
当然,如果不理解或不熟悉XPath语法,可以在浏览器的开发者工具中按照如下所示的方法查看元素的XPath语法,下图是在Chrome浏览器的开发者工具中查看豆瓣网电影详情信息中影片标题的XPath语法。
实现XPath解析需要三方库lxml
的支持,可以使用下面的命令安装lxml
。
pip install lxml
下面我们用XPath解析方式改写之前获取豆瓣电影Top250的代码,如下所示。
import random
import time
from lxml import etree
import requests
for page in range(1, 11):
resp = requests.get(
url=f'https://movie.douban.com/top250?start={(page - 1) * 25}',
headers={
'User-Agent': 'BaiduSpider',
}
)
tree = etree.HTML(resp.text)
# 通过XPath语法从页面中提取需要的数据
spans = tree.xpath('//*[@id="content"]/div/div[1]/ol/li/div/div[2]/div[1]/a/span[1]')
for span in spans:
print(span.text)
time.sleep(random.randint(1, 3))
CSS选择器解析
对于熟悉CSS选择器和JavaScript的开发者来说,通过CSS选择器获取页面元素可能是更为简单的选择,因为浏览器中运行的JavaScript本身就可以document
对象的querySelector()
和querySelectorAll()
方法基于CSS选择器获取页面元素。在Python中,我们可以利用三方库bs4
(BeautifulSoup)或pyquery
来做同样的事情。BeautifulSoup可以用来解析HTML和XML文档,修复含有未闭合标签等错误的文档,通过为待解析的页面在内存中创建一棵树结构,实现对从页面中提取数据操作的封装。可以用下面的命令来安装BeautifulSoup。
pip install beautifulsoup4
下面是使用bs4
改写的获取豆瓣电影Top250电影名称的代码。
import random
import time
import bs4
import requests
for page in range(1, 11):
resp = requests.get(
url=f'https://movie.douban.com/top250?start={(page - 1) * 25}',
headers={
'User-Agent': 'BaiduSpider',
}
)
soup = bs4.BeautifulSoup(resp.text, 'lxml')
# 通过CSS选择器从页面中提取需要的数据
spans = soup.select('div.info > div.hd > a > span:nth-child(1)')
for span in spans:
print(span.text)
time.sleep(random.randint(1, 3))
关于BeautifulSoup更多的知识,可以参考它的官方网站。
简单的总结
下面我们对三种解析方式做一个简单比较。
温馨提示:大家如果觉得这个专栏还不错, 一定记得点赞收藏哟!