时间: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 kilometrescssselect方法,我们可以利用CSS语法来选择表格中ID为places_area__row的行元素,然后是类为w2p_fw的子表格数据标签。由于cssselect返回的是一个列表,我们需要获取其中的第一个结果,并调用text_content方法,以迭代所有子元素并返回每个元素的相关文本。在本例中,尽管我们只有一个元素,但是该功能对于更加复杂的抽取示例来说非常有用。关键词:方法