一、Selectors选择器简介
文档地址:https://scrapy-chs.readthedocs.io/zh_CN/latest/intro/overview.html
从网页中提取数据有很多方法。Scrapy使用了一种基于 XPath 和 CSS表达式机制。
当抓取网页时,你做的最常见的任务是从HTML源码中提取数据。现有的一些库可以达到这个目的:
BeautifulSoup是在程序员间非常流行的网页分析库,它基于HTML代码的结构来构造一个Python对象, 对不良标记的处理也非常合理,但它有一个缺点:慢。
lxml是一个基于 ElementTree(不是Python标准库的一部分)的python化的XML解析库(也可以解析HTML)。
Scrapy提取数据有自己的一套机制。它们被称作选择器(seletors),因为他们通过特定的 XPath 或者 CSS 表达式来“选择” HTML文件中的某个部分。
XPath 是一门用来在XML文件中选择节点的语言,也可以用在HTML上。 CSS 是一门将HTML文档样式化的语言。选择器由它定义,并与特定的HTML元素的样式相关连。
Scrapy选择器构建于 lxml 库之上,这意味着它们在速度和解析准确性上非常相似。
二、使用选择器(selectors)
# 抓取地址
http://doc.scrapy.org/en/latest/_static/selectors-sample1.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>
1. 构造选择器
Scrapy selector是以 文字(text) 或 TextResponse
构造的 Selector
实例。 其根据输入的类型自动选择最优的分析方法(XML vs HTML):
>>> from scrapy.selector import Selector
>>> from scrapy.http import HtmlResponse
2. 以文字构造
>>> body = '<html><body><span>good</span></body></html>'
>>> Selector(text=body).xpath('//span/text()').extract()
['good']
3. 以response构造
>>> response = HtmlResponse(url='http://example.com', body=body, encoding='utf-8')
>>> Selector(response=response).xpath('//span/text()').extract()
['good']
response对象以 .selector 属性提供了一个selector, 您可以随时使用该快捷方法:
>>> response.selector.xpath('//span/text()').extract()
['good']
4. response.xpath() 与 response.css()
由于在response中使用XPath、CSS查询十分普遍,因此,Scrapy提供了两个实用的快捷方式,response.xpath() 及 response.css():
>>> response.xpath('//title/text()')
[<Selector xpath='//title/text()' data='Example Domain'>]
>>> response.css('title::text')
[<Selector xpath='descendant-or-self::title/text()' data='Example Domain'>]
.xpath()
及 .css()
方法返回一个类 SelectorList
的实例, 它是一个新选择器的列表。这个API可以用来快速的提取嵌套数据。
5. extract()
>>> response.xpath('//title/text()').extract()
['Example Domain']
注意:CSS选择器可以使用CSS3伪元素(pseudo-elements)来选择文字或者属性节点
>>> response.css('title::text').extract()
['Example Domain']
>>> response.css('title::text').extract()[0]
'Example Domain'
6. 嵌套选择器(selectors)
选择器方法( .xpath() or .css() )返回相同类型的选择器列表,因此你也可以对这些选择器调用选择器方法。
# 抓取地址
http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
>>> 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']
7. 结合正则表达式使用选择器
Selector
也有一个 .re()
方法,用来通过正则表达式来提取数据。然而,不同于使用 .xpath()
或者 .css()
方法, .re()
方法返回unicode字符串的列表。所以你无法构造嵌套式的 .re()
调用。
# 抓取地址
http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
>>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
[u'My image 1',
u'My image 2',
u'My image 3',
u'My image 4',
u'My image 5']
8. XPaths
记住如果你使用嵌套的选择器,并使用起始为 / 的XPath,那么该XPath将对文档使用绝对路径,而且对于你调用的 Selector 不是相对路径。
比如,假设你想提取在 <div> 元素中的所有 <p> 元素。首先,你将先得到所有的 <div> 元素:
>>> divs = response.xpath('//div')
开始时,你可能会尝试使用下面的错误的方法,因为它其实是从整篇文档中,而不仅仅是从那些 <div> 元素内部提取所有的 <p> 元素:
>>> for p in divs.xpath('//p'): # 这是错误的-从整个文档中获取
... print p.extract()
下面是比较合适的处理方法(注意 .//p XPath的点前缀):
>>> for p in divs.xpath('.//p'): # extracts all <p> inside
... print p.extract()
另一种常见的情况将是提取所有直系 <p> 的结果:
>>> for p in divs.xpath('p'):
... print p.extract()
网友评论