用 Python 提取 HTML 源代码数据有很多现成的库,比如 lxml、BeautifulSoup、pyquery 等,当然如果会用正则表达式的话就不用在意这些了。而 Scrapy 框架则自带了专门的选择器 Selector,功能十分强大,并且可以根据输入类型自动选择最佳的解析规则。
直接使用
针对一段 HTML 代码,我们可以用如下方式构建 Selector 对象来提取数据:
>>> from scrapy.selector import Selector
>>> body = '<html><body><span>csdn</span></body></html>'
>>> Selector(text=body).xpath('//span/text()').get()
'csdn'
把 Scrapy 中的 Selector 单独拿出来,构建的时候传入 text 参数,就生成了一个 Selector 选择器对象,然后就可以调用 xpath()、css() 等方法来提取数据了。
下面将讲解使用选择器的用法,下面是用于测试的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>
构造响应:
>>> scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
Scrapy 发起了一次请求,然后把一些可操作的变量传递给我们,如request、response 等,而页面源码就是上面的 HTML 代码,并把内容赋值给 response
XPath选择器
先展示几个实例:
>>> result = response.selector.xpath('//a')
>>> result
[<Selector xpath='//a' data='<a href="image1.html">Name: My image 1 <'>,
<Selector xpath='//a' data='<a href="image2.html">Name: My image 2 <'>,
<Selector xpath='//a' data='<a href="image3.html">Name: My image 3 <'>,
<Selector xpath='//a' data='<a href="image4.html">Name: My image 4 <'>,
<Selector xpath='//a' data='<a href="image5.html">Name: My image 5 <'>]
>>> type(result)
scrapy.selector.unified.SelectorList
>>> result.xpath('./img')
[<Selector xpath='./img' data='<img src="image1_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image2_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image3_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image4_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image5_thumb.jpg">'>]
打印结果的形式是 Selector 组成的列表,最后获得了 a 节点里面的所有 img 节点
选择器的最前方加 . ,代表提取元素内部的数据,如果没有加点,则代表从根节点开始提取。此处我们用了./img
的提取方式,则代表从 a 节点里进行提取。如果此处我们用 //img
,则还是从 html 节点里进行提取。
提取具体内容:
>>> response.xpath('//a/text()').extract()
['Name: My image 1 ', 'Name: My image 2 ', 'Name: My image 3 ', 'Name: My image 4 ', 'Name: My image 5 ']
>>> response.xpath('//a/@href').extract()
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
>>> response.xpath('//a[@href="image1.html"]/text()').extract()
['Name: My image 1 ']
CSS选择器
上面提取所有 a 结点的过程用 CSS 选择器同样可以做到,如下所示:
>>> response.css('a')
[<Selector xpath='descendant-or-self::a' data='<a href="image1.html">Name: My image 1 <'>,
<Selector xpath='descendant-or-self::a' data='<a href="image2.html">Name: My image 2 <'>,
<Selector xpath='descendant-or-self::a' data='<a href="image3.html">Name: My image 3 <'>,
<Selector xpath='descendant-or-self::a' data='<a href="image4.html">Name: My image 4 <'>,
<Selector xpath='descendant-or-self::a' data='<a href="image5.html">Name: My image 5 <'>]
提取具体内容:
>>> response.css('a[href="image1.html"]').extract()
['<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>']
>>> response.css('a[href="image1.html"] img').extract()
['<img src="image1_thumb.jpg">']
>>> response.css('a[href="image1.html"] img').extract_first()
'<img src="image1_thumb.jpg">'
正则匹配
a 节点中的文本类似于 Name: My image 1,若只想把 Name: 后面的内容提取出来,就可以借助 re()
方法,实现如下:
>>> response.xpath('//a/text()').re('Name:\s(.*)')
['My image 1 ', 'My image 2 ', 'My image 3 ', 'My image 4 ', 'My image 5 ']
给 re()
方法传了一个正则表达式,其中 (.*)
就是要匹配的内容,输出的结果就是正则表达式匹配的分组,结果会依次输出
还有:
>>> response.xpath('//a/text()').re_first('(.*?):\s(.*)')
'Name'
>>> response.xpath('//a/text()').re_first('Name:\s(.*)')
'My image 1 '