检查文本中是不是存在大量关键字
Posted
技术标签:
【中文标题】检查文本中是不是存在大量关键字【英文标题】:Checking Text for The Presence of a Large Set of Keywords检查文本中是否存在大量关键字 【发布时间】: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()
【问题讨论】:
【参考方案1】:您还可以检查关键字是否在response.body
内:
source = response.body
with open('input.txt') as f:
for word in f:
print word, word.strip() in source
或者,使用any()
:
with open('input.txt') as f:
print any(word.strip() in source for word in f)
【讨论】:
感谢您的回复!打开文件 -> 在文件中读取单词的方法比我想象的要少得多。但是,我最初的措辞不准确;我不想检查关键字是否存在,至少将其中一个关键字设置为我的解析条件。这个破碎的代码可能会让您更清楚地了解我的目标:使用 open('keys.txt') as keyword_list: if response.xpath('//*[text()[contains(., word在关键字列表中)]]'): 感谢您的更新。它运行并告诉我列表中的单词之一是否在 response.body 中匹配;这很好,但这不是我想要的。我想首先将关键字的存在作为抓取数据的条件。我将更新我的原始问题以澄清这一点并提供一些背景信息。顺便说一句,为什么要定义'source'而不是写` print any(word.strip() in response.body for word in f)`?【参考方案2】:正则表达式可能是在大量页面上运行测试的最快方法
import re
keywords = '|'.join(re.escape(word.strip()) for word in open('keywords.txt'))
r = re.compile('.*(%s).*' % keywords, re.MULTILINE|re.UNICODE)
if r.match(response.body_as_unicode()):
在多个关键字上生成 xpath 表达式可能有效,但在运行 XPATH 之前将页面解析为 XML 会增加额外的 CPU 负载(通常约为 100 毫秒)。
【讨论】:
谢谢,这看起来很有希望。但是,让您的解决方案运行以便我可以对其进行测试时,我遇到了一些麻烦。您定义关键字的行返回错误TypeError: "'builtin_function_or_method' object is not iterable"
,我从这篇帖子link 中收集到这意味着直接调用了一个方法。不幸的是,我看不到在哪里。
自从昨晚遇到错误并更改为word.strip()
和response.body_as_unicode()
分别处理我上面提到的错误和TypeError: "expected string or buffer" that's triggered by using
word.strip() `单独。不幸的是,这些更改似乎也破坏了我之前测试的 parse 方法。调试响应表明它抓取了我期望的所有响应,但它现在返回 Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
。
我根据您的反馈修复了错误。看来你早点解决了。我希望你能用这种方法衡量显着的性能改进?以上是关于检查文本中是不是存在大量关键字的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Data 中的 exists 关键字来检查实体是不是存在?