scrapy作为爬虫框架还是比较全能的,但是我之前遇到过一个问题就是要将一个节点的某些子节点删除,这个操作好像scrapy的selector好像不能实现,也有可能是我自己没找到方法。我的解决方法是直接将response的内容构建成lxml然后再进行节点删除和信息提取。
1.如何构建对象
首先我们要引入lxml(html也是lxml的一种)包,然后调用etree.HTML()
函数解析html来构建Element
1 | from lxml import etree |
2.去除特定节点
构建完对象后,我们选择find
,findall
,getchildren
等方法选定想要剔除的节点,然后再调用remove
函数将其去掉,Element还有很多的方法我也没有全部用过,如果有需要可以参见lxml官方文档。
1 | for pp in element.findall('p[@style]'): |
3.完成信息提取
之后就是正常的完成对所需信息的处理,去毛刺,格式化,列表化等操作:
1 | content = element.xpath('string(.)').replace('\xa0', '').replace('a("conten");', '').split('\n') |
注意:
- 虽然
Element
和scrapy的selector
都可以是调用xpath
方法形式上也很类似但是Element
对象xpath('string(.)')
之后是不用extract_first()
的
4.extract()和extract_first()
如果您是Scrapy的长期用户,则可能熟悉.extract()
和.extract_first()
选择器方法。许多博客文章和教程也正在使用它们。Scrapy仍支持这些方法,没有计划弃用它们。
但是,Scrapy用法文档现在使用.get()
和 .getall()
方法编写。我们认为这些新方法可以使代码更简洁易读。
以下示例显示了这些方法如何相互映射:
SelectorList.get()
与SelectorList.extract_first()
:
1 | >> response.css('a::attr(href)').get() |
SelectorList.getall()
与SelectorList.extract()
:
1 | >> response.css('a::attr(href)').getall() |
Selector.get()
与Selector.extract()
:
1 | >> response.css('a::attr(href)')[0].get() |
- 为了保持一致性,还有
Selector.getall()
,它返回一个列表:
1 | >> response.css('a::attr(href)')[0].getall() |
因此,主要区别在于.get()
和.getall()
方法的输出更可预测:.get()
始终返回单个结果,.getall()
始终返回所有提取结果的列表。使用.extract()
method时,结果是否为列表并不总是很明显;得到一个结果.extract()
或者.extract_first()
应该被调用。