使用lxml抓取网页
现在越来越多的网站提供了API。早前,我们之前已经谈论过XML-RPC和REST。即使网站服务正以指数方式增长,但仍然有一些网站提供的信息很松散。特别是政府的网站。如果你对这些网站上的内容着迷,你唯一的选择就是抓取网页。
什么是抓取网页?
抓取网页是一种用编程模仿人类浏览网站的技术。为了能在你的程序里能够抓取网页,你需要的工具:
- 向网站发出HTTP请求
- 解析HTTP的响应信息并且提取内容
用urllib生成HTTP请求,一个标准的Python类模块。一旦你通过网站获得原始的HTML,就需要一种效率的方式去提取内容。
许多程序员谈论到从文本文件中提取信息的时候,很快就会想到用正则表达式。
但是,有一个更好的处理工具。lxml登场,使用类似lxml的工具,你可以把一个HTML文件转换为XML文件。毕竟,一个XHTML文件属于XML文件的一种。就我们知道的网站作者很少关心HTML文件的规范。大部分的网站有不完整的HTML语言。我们必须要处理它们。
但嘿,lxml可以很好的处理。甚至如果你应用在一个不完整的HTML文件,lxml的HTML解析器可以转换成有效的XML文件。但是,在网站抓取时,正则表达式仍然有用。你可以结合着lxml使用正则表达式,特别是当你处理文本节点的时候。
在开始之前你应该知道什么?
- XML
- Xpath
- 一点点的Python
W3Schools.com 在这些科目上都有很好的教程,可以去XML tutorial和Xpath tutorial去提高你的知识。
让我们写一个python脚本来练习新学习到的技能。
印度政府有一个列举一些荣誉国会成员的网页。这次练习的目标就是抓取这个网页并且提取荣誉国会成员的名字。
练习的网页地址是:http://164.100.47.132/LssNew/Members/Alphabaticallist.aspx
抛开纷乱,让我们开始编码:
import urllib from lxml import etree import StringIO
我们可以用urllib模块、lxml、etree抓取网页,并且有了必须得解析对象
result = urllib.urlopen("http://164.100.47.132/LssNew/Members/Alphabaticallist.aspx") html = result.read()
在这一点上,我们有了原始的HTML
parser = etree.HTMLParser() tree = etree.parse(StringIO.StringIO(html), parser)
我们创建HTML解析器对象,然后把解析器传递给etree。换句话说,我们告诉etree解析先前的HMLT解析对象。我们也可以使用StringIO.StringIO把文件传递给字符串对象\
现在,看一下文件的源代码
我们想要的信息在id为” ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1”的表格里
让我们开始构建XPath表达式,为了向里挖掘我们关心部分的数据
//table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']
以上的XPath表达式需要id抓取表格节点
“ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1”位于文件
第一行,<tr>,虽然包含表格头部但不是必要的,让我们抓取表格元素中除了第一行所有的行
/table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']/tr[position()>1]在每个行里,国会成员的名字在第二个单元格<td>中。
过滤XPath表达式,只返回每一行的第二个单元格
//table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']/tr[position()>1]/td[position()=2]
进入我们的目标节点单元,国会成员的名字被包含在<a>标签里
重新定义XPath表达式,抓起文本节点
//table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']/tr[position()>1]/td[position()=2]/a/child::text()
应用XPath表达式在我们的树上,
xpath = "//table[@id='ctl00_ContPlaceHolderMain_Alphabaticallist1_dg1']/tr[position()>1]/td[position()=2]/a/child::text()" filtered_html = tree.xpath(xpath)这就是所有我们抓取国会成员名字的代码
filtered_html 变量是一个python列表。列表中的元素国会成员的名字
自己亲自尝试,并查看结果
print filtered_html
实例输出如下:
['Aaroon Rasheed,Shri J.M.', 'Abdul Rahman,Shri ', 'Abdullah,Dr. Farooq', 'Acharia,Shri Basudeb', ...]
当你读到这个文档,如果这个网页已经被移动或者它的内容已改变。请参考attached HTML document.
全部的脚本发表在了gist
欢迎标记和搜索这篇文章
附件 Size
members-of-the-parliment.html 455.22 KB