对 lxml 的 scrapy 响应选择器
scrapy response selector to lxml
的确,这个问题我仔细看了。
但是在我的项目中,有几十个爬虫使用了scrapy selector。逐行将scrapy转换成lxml会花费我们很多时间。所以我尝试写一些兼容的代码来迁移爬虫
class ElemList(list):
def __init__(self, elem_list=[]):
super(ElemList, self).__init__(elem_list)
def xpath(self, xpath_str=""):
res = []
for elem in self:
try:
e = elem.xpath(xpath_str)
except Exception as e:
continue
if isinstance(e, str) or isinstance(e, unicode):
res.append(e)
else:
res.extend(e)
return ElemList(res)
def extract(self):
res = []
for elem in self:
if isinstance(elem, str):
res.append(elem)
return res
响应 class,添加一些初始化调用。
from lxml import etree
class Response(object):
def __init__(self):
self.elem_list = ElemList(etree.HTML(self.html))
def xpath(self, xpath):
return self.elem_list.xpath(xpath)
有了这个class,我就可以像这样调用响应对象:
resp.xpath('//h2[@class="user-card-name"]/text()').extract()
resp.xpath('//h2[@class="user-card-name"]').xpath('*[@class="top-badge"]/a/@href').extract()
有效。但是新的问题来了,如何迁移response.css这样的?
baseInfo_div = response.css(".vcard")[0]
baseInfo_div.css(".vcard-fullname")
baseInfo_div.css(".vcard-username")
baseInfo_div.css('li[itemprop="worksFor"]')
baseInfo_div.css('li[itemprop="homeLocation"]')
您可以尝试使用 cssselect()
method from lxml.cssselect
来实现您的逻辑,这使您可以使用 CSS 选择器表达式从 lxml
的 Element
对象中进行查询。或者您可以使用 GenericTranslator.css_to_xpath()
将 CSS 选择器转换为 XPath 选择器:
from lxml import html
h = html.fromstring('''<div id="outer">
<div id="inner" class="content body">
text
</div></div>''')
content = h.cssselect('div.content')[0]
content.text
# output :
# '\n text\n'
from cssselect import GenericTranslator
GenericTranslator().css_to_xpath('div.content')
# output :
# u"descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' content ')]"
的确,这个问题
class ElemList(list):
def __init__(self, elem_list=[]):
super(ElemList, self).__init__(elem_list)
def xpath(self, xpath_str=""):
res = []
for elem in self:
try:
e = elem.xpath(xpath_str)
except Exception as e:
continue
if isinstance(e, str) or isinstance(e, unicode):
res.append(e)
else:
res.extend(e)
return ElemList(res)
def extract(self):
res = []
for elem in self:
if isinstance(elem, str):
res.append(elem)
return res
响应 class,添加一些初始化调用。
from lxml import etree
class Response(object):
def __init__(self):
self.elem_list = ElemList(etree.HTML(self.html))
def xpath(self, xpath):
return self.elem_list.xpath(xpath)
有了这个class,我就可以像这样调用响应对象:
resp.xpath('//h2[@class="user-card-name"]/text()').extract()
resp.xpath('//h2[@class="user-card-name"]').xpath('*[@class="top-badge"]/a/@href').extract()
有效。但是新的问题来了,如何迁移response.css这样的?
baseInfo_div = response.css(".vcard")[0]
baseInfo_div.css(".vcard-fullname")
baseInfo_div.css(".vcard-username")
baseInfo_div.css('li[itemprop="worksFor"]')
baseInfo_div.css('li[itemprop="homeLocation"]')
您可以尝试使用 cssselect()
method from lxml.cssselect
来实现您的逻辑,这使您可以使用 CSS 选择器表达式从 lxml
的 Element
对象中进行查询。或者您可以使用 GenericTranslator.css_to_xpath()
将 CSS 选择器转换为 XPath 选择器:
from lxml import html
h = html.fromstring('''<div id="outer">
<div id="inner" class="content body">
text
</div></div>''')
content = h.cssselect('div.content')[0]
content.text
# output :
# '\n text\n'
from cssselect import GenericTranslator
GenericTranslator().css_to_xpath('div.content')
# output :
# u"descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' content ')]"