当您抓取网页时,您需要执行的最常见任务是从HTML源中提取数据。有几个图书馆可以实现这一点:

  • BeautifulSoup 是Python程序员中非常受欢迎的Web抓取库,它基于HTML代码的结构构建了一个Python对象,并且还可以很好的处理不好的标记,但它有一个缺点:它很慢。
  • lxml 是一个基于 ElementTree 的pythonic API的XML解析库(也解析HTML)。 (lxml不是Python标准库的一部分。)

Scrapy具有自己的提取数据的机制。它们被称为选择器,因为它们“选择”由XPathCSS表达式指定的HTML文档的某些部分。

XPath是用于选择XML文档中的节点的语言,也可以与HTML一起使用。CSS是将样式应用于HTML文档的语言。它定义选择器将这些样式与特定的HTML元素相关联。

刮板选择器是通过lxml库构建的,这意味着它们的速度和解析精度非常相似。

这个页面解释了选择器如何工作和描述他们的API是非常小而简单的,不像lxmlAPI更大,因为lxml库可以用于许多其他任务,除了选择标记文档。

有关选择器API的完整参考,请参阅选择器参考

使用选择器

构造选择器

Scrapy选择器是通过传递文本TextResponse对象构建的Selector类的实例。它根据输入类型自动选择最佳解析规则(XML vs HTML):

>>> from scrapy.selector import Selector
>>> from scrapy.http import HtmlResponse

从文本构建:

>>> body = '<html><body><span>good</span></body></html>'
>>> Selector(text=body).xpath('//span/text()').extract()
[u'good']

从响应构建:

>>> response = HtmlResponse(url='http://example.com', body=body)
>>> Selector(response=response).xpath('//span/text()').extract()
[u'good']

为方便起见,响应对象在.selector属性上显示选择器,可以使用此快捷方式完全可以:

>>> response.selector.xpath('//span/text()').extract()
[u'good']

使用选择器

为了解释如何使用选择器,我们将使用Scrapy shell(提供交互式测试)和Scrapy文档服务器中的示例页面:

http://doc.scrapy.org/en/latest/_static/selectors-sample1.html

这是它的HTML代码:

<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5.html'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
  </div>
 </body>
</html>

首先,我们来打开shell:

scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html

然后,在shell加载之后,您将使响应可用作为responseshell变量,并将其附加的选择器作为response.selector属性。

由于我们处理HTML,所以选择器将自动使用HTML解析器。

因此,通过查看该页面的HTML代码,我们来构建一个XPath来选择标题标签中的文本:

>>> response.selector.xpath('//title/text()')
[<Selector (text) xpath=//title/text()>]

使用XPath和CSS查询响应是如此常见,响应包括两个方便的快捷方式:response.xpath()response.css()

>>> response.xpath('//title/text()')
[<Selector (text) xpath=//title/text()>]
>>> response.css('title::text')
[<Selector (text) xpath=//title/text()>]

您可以看到,.xpath().css()方法返回一个SelectorList实例,它是一个新的选择器列表。该API可用于快速选择嵌套数据:

>>> response.css('img').xpath('@src').extract()
[u'image1_thumb.jpg',
 u'image2_thumb.jpg',
 u'image3_thumb.jpg',
 u'image4_thumb.jpg',
 u'image5_thumb.jpg']

要实际提取文本数据,您必须调用选择器.extract()方法,如下所示:

>>> response.xpath('//title/text()').extract()
[u'Example website']

如果要仅提取第一个匹配的元素,可以调用选择器.extract_first()

>>> response.xpath('//div[@id="images"]/a/text()').extract_first()
u'Name: My image 1 '

如果没有找到元素,则返回None

>>> response.xpath('//div[@id="not-exists"]/text()').extract_first() is None
True

默认返回值可以作为参数提供,而不是使用None

>>> response.xpath('//div[@id="not-exists"]/text()').extract_first(default='not-found')
'not-found'

请注意,CSS选择器可以使用CSS3伪元素选择文本或属性节点:

>>> response.css('title::text').extract()
[u'Example website']

现在我们要获得基本URL和一些图像链接:

>>> response.xpath('//base/@href').extract()
[u'http://example.com/']

>>> response.css('base::attr(href)').extract()
[u'http://example.com/']

>>> response.xpath('//a[contains(@href, "image")]/@href').extract()
[u'image1.html',
 u'image2.html',
 u'image3.html',
 u'image4.html',
 u'image5.html']

>>> response.css('a[href*=image]::attr(href)').extract()
[u'image1.html',
 u'image2.html',
 u'image3.html',
 u'image4.html',
 u'image5.html']

>>> response.xpath('//a[contains(@href, "image")]/img/@src').extract()
[u'image1_thumb.jpg',
 u'image2_thumb.jpg',
 u'image3_thumb.jpg',
 u'image4_thumb.jpg',
 u'image5_thumb.jpg']

>>> response.css('a[href*=image] img::attr(src)').extract()
[u'image1_thumb.jpg',
 u'image2_thumb.jpg',
 u'image3_thumb.jpg',
 u'image4_thumb.jpg',
 u'image5_thumb.jpg']

嵌套选择器

选择方法(.xpath().css())返回相同类型的选择器列表,因此也可以为这些选择器调用选择方法。这里有一个例子:

>>> links = response.xpath('//a[contains(@href, "image")]')
>>> links.extract()
[u'<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>',
 u'<a href="image2.html">Name: My image 2 <br><img src="image2_thumb.jpg"></a>',
 u'<a href="image3.html">Name: My image 3 <br><img src="image3_thumb.jpg"></a>',
 u'<a href="image4.html">Name: My image 4 <br><img src="image4_thumb.jpg"></a>',
 u'<a href="image5.html">Name: My image 5 <br><img src="image5_thumb.jpg"></a>']

>>> for index, link in enumerate(links):
...     args = (index, link.xpath('@href').extract(), link.xpath('img/@src').extract())
...     print 'Link number %d points to url %s and image %s' % args

Link number 0 points to url [u'image1.html'] and image [u'image1_thumb.jpg']
Link number 1 points to url [u'image2.html'] and image [u'image2_thumb.jpg']
Link number 2 points to url [u'image3.html'] and image [u'image3_thumb.jpg']
Link number 3 points to url [u'image4.html'] and image [u'image4_thumb.jpg']
Link number 4 points to url [u'image5.html'] and image [u'image5_thumb.jpg']

使用正则表达式的选择器

Selector也有一个使用正则表达式提取数据的.re()方法。但是,与.xpath().css()方法不同,.re()返回一个unicode字符串列表。所以你不能构造嵌套的.re()调用。

以下是从上述HTML代码中提取图像名称的示例:

>
>
>
回应
。
xpath
(
'// a [contains(@href,“image”)] / text()'
)
。
re
(
r'Name
:\ s *(。*)'
)
[u'My image 1',
你是我的形象2',
你的形象3',
你的形象4',
你的形象5']

还有一个额外的帮助.extract_first().re().re_first(),命名为.re_first()。使用它来提取第一个匹配的字符串:

使用相对的XPath¶

请记住,如果您正在嵌套选择器并使用以/开头的XPath,XPath对于文档将是绝对的,而不是相对于您从其中调用的Selector

例如,假设您要提取<div>元素内的所有<p><div>元素。首先,你会得到所有的<div>元素:

>
>
>
divs
=
response
。
xpath
(
'// div'
)

首先,您可能会尝试使用以下方法,这是错误的,因为它实际上从文档中提取所有<p>元素,而不仅仅是<div>元素中的元素:

>
>
>
for
p
in
divs
xpath
(
'// p'
):
#这是错误的 - 从整个文档中获取所有的
<
p
>
...
打印
p
。
提取
()

这是正确的方法(注意点前面的.//pXPath):

>
>
>
for
p
in
divs
xpath
(
'.//p'
):
#提取内部的所有
<
p
>
...
打印
p
。
提取
()

另一个常见的情况是提取所有直接的<p>子代:

>
>
>
for
p
in
divs
xpath
(
'p'
):
...
打印
p
。
提取
()

有关相对XPath的更多详细信息,请参阅XPath规范中的“位置路径”部分。

XPath表达式中的变量

XPath允许您使用$somevariable语法来引用XPath表达式中的变量。这有点类似于SQL世界中的参数化查询或准备语句,您可以用查询中的某些参数替换占位符,例如,然后用查询传递的值替换它们。

下面是一个例子来匹配一个基于其“id”属性值的元素,而不用硬编码(以前显示):

在表达式中使用
>
>
>
$``````````````````````````````````````
>
>
>
回应
。
xpath
(
'// div [@ id = $ val] / a / text()'
,
val
=
'images'
)
。
extract_first
()
你的名字:我的形象1'

这是另一个例子,找到包含五个<a><a><div>标签的“id”属性(这里我们将值5作为整数传递):

>
>
>
回应
。
xpath
(
'// div [count(a)= $ cnt] / @ id'
,
cnt
=
5
)
。
extract_first
()
u'images'

调用.xpath()时,所有的变量引用必须有一个绑定值(否则你会得到一个ValueError:XPatherror:异常)。这是通过传递必要的命名参数来完成的。

parsel,图书馆供电Scrapy选择器,有更多的细节和XPath变量的例子。

results matching ""

    No results matching ""