时间:2023-06-08 03:21:02 | 来源:网站运营
时间:2023-06-08 03:21:02 来源:网站运营
3种网页抓取方法:3种抓取其中数据的方法。首先是正则表达式,然后是流行的BeautifulSoup
模块,最后是强大的lxml
模块。https://docs.python.org/2/howto/regex.html
获得完整介绍。即使你使用过其他编程语言的正则表达式,我依然推荐你一步一步温习一下Python中正则表达式的写法。code
目录中运行,以便导入工作正常。如果你希望创建一个不同的结构,请注意需要变更所有来自其他章的导入操作(比如下述代码中的from chp1.advanced_link_crawler
)。>>>
import re
>>>
from chp1.advanced_link_crawler import download
>>> url =
'http://example.python-scraping.com/view/UnitedKingdom-239'
>>> html = download(url)
>>> re.findall(r'(.*?)', html)
['<img />
',
'244,820 square kilometres',
'62,348,447',
'GB',
'United Kingdom',
'London',
'<a>EU</a>
',
'.uk',
'GBP',
'Pound',
'44',
'@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',
'^(([A-Z]d{2}[A-Z]{2})|([A-Z]d{3}[A-Z]{2})|([A-Z]{2}d{2} [A-Z]{
2})|([A-Z]{2}d{3}[A-Z]{2})|([A-Z]d[A-Z]d[A-Z]{2}) |([A-Z]{2}d[A-Z]
d[A-Z]{2})|(GIR0AA))$',
'en-GB,cy-GB,gd',
'<div><a>IE </a></div>
']
>>> re.findall('(.*?)', html)[1]
'244,820 square kilometres'
>>> re.findall('<label for="places_area">Area: </label>
(.*?)', html)
['244,820 square kilometres']
`标签之间添加多余的空格,或是变更
area_label`等。下面是尝试支持这些可能性的改进版本。>>> re.findall('''.*?<tds>(.*?)''', html)
['244,820 square kilometres']
`标签里添加
title属性,或者
tr、
td`元素修改了它们的CSS类或ID。pip install beautifulsoup4
<ul>
<li>Area
</li><li>Population
</li></ul>
Population
列表项被解析为Area
列表项的子元素,而不是并列的两个列表项的话,我们在抓取时就会得到错误的结果。下面让我们看一下Beautiful Soup是如何处理的。>>>
from bs4 import
BeautifulSoup
>>>
from pprint import pprint
>>> broken_html =
'<ul><li>Area</li><li>Population</li></ul>
'
>>>
# parse the HTML
>>> soup =
BeautifulSoup(broken_html,
'html.parser')
>>> fixed_html = soup.prettify()
>>> pprint(fixed_html)
<ul>
<li>
Area
</li><li>
Population
</li>
</ul>
html.parser
并没有得到正确解析的HTML。从前面的代码片段可以看出,由于它使用了嵌套的li
元素,因此可能会导致定位困难。幸运的是,我们还有其他解析器可以选择。我们可以安装LXML(2.2.3节中将会详细介绍),或使用html5lib
。要想安装html5lib
,只需使用pip
。pip install html5lib
>>> soup =
BeautifulSoup(broken_html,
'html5lib')
>>> fixed_html = soup.prettify()
>>> pprint(fixed_html)
<ul>
<li>
Area
</li>
<li>
Population
</li>
</ul>
html5lib
的BeautifulSoup
已经能够正确解析缺失的属性引号以及闭合标签,并且还添加了和
标签,使其成为完整的HTML文档。当你使用lxml
时,也可以看到类似的结果。find()
和find_all()
方法来定位我们需要的元素了。>>> ul = soup.find('ul', attrs={'class':'country_or_district'})
>>> ul.find('li')
# returns just the first match
<li>Area</li>
>>> ul.find_all('li')
# returns all matches
[<li>Area</li>
,
<li>Population</li>
>>>
from bs4 import
BeautifulSoup
>>> url =
'http://example.python-scraping.com/places/view/United-Kingdom-239'
>>> html = download(url)
>>> soup =
BeautifulSoup(html)
>>>
# locate the area row
>>> tr = soup.find(attrs={'id':'places_area__row'})
>>> td = tr.find(attrs={'class':'w2p_fw'})
# locate the data element
>>> area = td.text # extract the text from the data element
>>>
print(area)
244,820 square kilometres
libxml2
这一XML解析库构建的Python库,它使用C语言编写,解析速度比Beautiful Soup更快,不过安装过程也更为复杂,尤其是在Windows中。最新的安装说明可以参考http://lxml.de/installation.html
。如果你在自行安装该库时遇到困难,也可以使用Anaconda来实现。PYTHON_PATH
设置为Conda的Python安装位置。lxml
模块的第一步也是将有可能不合法的HTML解析为统一格式。下面是使用该模块解析同一个不完整HTML的例子。>>>
from lxml.html import fromstring, tostring
>>> broken_html =
'<ul><li>Area</li><li>Population</li></ul>
'
>>> tree = fromstring(broken_html)
# parse the HTML
>>> fixed_html = tostring(tree, pretty_print=True)
>>>
print(fixed_html)
<ul>
<li>Area</li>
<li>Population</li>
</ul>
lxml
也可以正确解析属性两侧缺失的引号,并闭合标签,不过该模块没有额外添加和
标签。这些都不是标准XML的要求,因此对于lxml
来说,插入它们并不是必要的。lxml
有几种不同的方法,比如XPath选择器和类似Beautiful Soup的find()
方法。不过,在本例中,我们将会使用CSS选择器,因为它更加简洁,并且能够在第5章解析动态内容时得以复用。一些读者可能由于他们在jQuery选择器方面的经验或是前端Web应用开发中的使用对它们已经有所熟悉。在本章的后续部分,我们将对比这些选择器与XPath的性能。要想使用CSS选择器,你可能需要先安装cssselect
库,如下所示。pip install cssselect
lxml
的CSS选择器,抽取示例页面中的面积数据了。>>> tree = fromstring(html)
>>> td = tree.cssselect('tr#places_area__row > td.w2p_fw')[0]
>>> area = td.text_content()
>>>
print(area)
244,820 square kilometres
cssselect
方法,我们可以利用CSS语法来选择表格中ID为places_area__row
的行元素,然后是类为w2p_fw
的子表格数据标签。由于cssselect
返回的是一个列表,我们需要获取其中的第一个结果,并调用text_content
方法,以迭代所有子元素并返回每个元素的相关文本。在本例中,尽管我们只有一个元素,但是该功能对于更加复杂的抽取示例来说非常有用。关键词:方法