【发布时间】:2015-11-01 04:55:04
【问题描述】:
假设我想检查一个网页是否存在任意数量的关键字。我该怎么做呢?
我已经测试了 xpath 选择器if response.xpath('//*[text()[contains(.,"red") or contains(.,"blue") or contains(.,”green”)]]'):,它按预期工作。我有兴趣检查的实际关键字集太大而无法方便地手动输入,如上所述。我感兴趣的是一种通过根据填充了关键词的文件的内容生成选择器来自动化该过程的方法。
从一个每个关键字都在一行的文本文件开始,我如何打开该文件并使用它来检查它包含的关键字是否出现在给定 xpath 的文本元素中?
我使用线程 Xpath contains value A or value B 和 XPATH Multiple Element Filters 提出了我的手动输入解决方案,但没有找到任何解决自动化问题的方法。
澄清
我对只检查给定的 xpath 是否包含我的列表中提供的任何关键字不感兴趣。我还想使用他们的存在作为从页面中抓取内容的先决条件。我测试过的手动系统的工作原理如下:
item_info = ItemLoader(item=info_categories(), response=response)
if response.xpath('//*[text()[contains(.,"red") or contains(.,"blue") or contains(.,”green”)]]'):
item_info.add_xpath('title', './/some/x/path/text()')
item_info.add_xpath('description', './/some/other/x/path/text()')
return item_info.load_item()
虽然@alecxe 的解决方案允许我根据关键字集检查页面文本,但从“打印”切换到“如果”并尝试控制我提取的信息返回SyntaxError: invalid syntax。我可以将从列表中读取关键字的便利性与手动输入它们的功能结合起来吗?
更新——探索 Frederic Bazin 的正则表达式解决方案
在过去的几天里,我一直在使用正则表达式方法来限制我的解析。我的代码采用了 Frederic 的提议并进行了一些修改以解决错误,如下所示:
item_info = ItemLoader(item=info_categories(), response=response)
keywords = '|'.join(re.escape(word.strip()) for word in open('keys.txt'))
r = re.compile('.*(%s).*' % keywords, re.MULTILINE|re.UNICODE)
if r.match(response.body_as_unicode()):
item_info.add_xpath('title', './/some/x/path/text()')
item_info.add_xpath('description', './/some/other/x/path/text()')
return item_info.load_item()
这段代码运行没有错误,但 Scrapy 报告 0 个项已爬取和 0 个项已被抓取,因此显然有问题。
我试图通过从 Scrapy shell 运行它来进行调试。我的结果表明keywords 和r 步骤都在正常运行。如果我使用上述方法为包含红色、蓝色和绿色字样的 .txt 文件定义并调用 keywords,我会收到 'red|blue|green' 的响应。如上所述定义和调用r 给了我<_sre.SRE_Pattern object at 0x17bc980>,我相信这是预期的响应。但是,当我运行 r.match(response.body_as_unicode()) 时,我没有收到任何响应,即使在我知道包含我的一个或多个关键字的页面上也是如此。
有人对我在这里缺少什么有想法吗?据我了解,只要我的一个关键字出现在 response.body 中,就应该触发匹配,并且 Scrapy 应该继续使用我定义的 xpath 从该响应中提取信息。显然我错了,但我不确定如何或为什么。
解决方案?
我想我可能终于解决了这个问题。我目前的结论是,困难是由在response.body_as_unicode 上执行r.match 造成的。 here 提供的文档说匹配:
如果字符串开头的零个或多个字符与正则表达式模式匹配,则返回相应的 MatchObject 实例。如果字符串与模式不匹配,则返回 None;请注意,这与零长度匹配不同。
请注意,即使在 MULTILINE 模式下,re.match() 也只会匹配字符串的开头,而不是每行的开头。
这种行为不适合我的情况。我有兴趣从其中包含我的关键字anywhere的页面中识别和抓取信息,而不是那些将我的一个关键字作为页面上第一个项目的页面。为了完成这个任务,我需要re.search,它会扫描一个字符串,直到找到compile 生成的正则表达式模式的匹配项,并返回MatchObject,否则在模式不匹配时返回None。
我当前的(工作!)代码如下。请注意,除了从 match 切换到 search 之外,我还在关键字定义中添加了一些内容,以限制匹配整个单词。
item_info = ItemLoader(item=info_categories(), response=response)
keywords = '|'.join(r"\b" + re.escape(word.strip()) + r"\b" for word in open('keys.txt'))
r = re.compile('.*(%s).*' % keywords, re.MULTILINE|re.UNICODE)
if r.search(response.body_as_unicode()):
item_info.add_xpath('title', './/some/x/path/text()')
item_info.add_xpath('description', './/some/other/x/path/text()')
return item_info.load_item()
【问题讨论】:
标签: python html xpath web-scraping scrapy