假設我想檢查網頁中是否存在任意數量的關鍵字。我會怎麼做呢?檢查文本是否存在一大組關鍵字
我測試了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
。我可以將列表中關鍵字的閱讀方便性與手動輸入它們的功能結合起來嗎?
更新,探索弗雷德裏克·巴讚的正則表達式的解決方案
在過去的幾天裏,我一直與一個正則表達式的方法來限制我的解析。我的代碼,它採用弗雷德裏克與一些修改建議,考慮到誤差,如下:
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
步驟都是行爲。如果我使用上述方法爲包含單詞red,blue和green的.txt文件定義並調用keywords
,我會收到'red|blue|green'
。如上所述定義和調用r
給我<_sre.SRE_Pattern object at 0x17bc980>
,我相信這是預期的響應。但是,當我運行r.match(response.body_as_unicode())
時,即使在我知道的包含一個或多個關鍵字的頁面上,我也沒有收到任何回覆。
有沒有人有想過我在這裏失蹤的想法?據我所知,無論何時我的關鍵字出現在response.body中,都應該觸發匹配,並且Scrapy應該繼續使用我定義的xpaths從該響應中提取信息。顯然我錯了,但我不知道如何或爲什麼。
解決方案?
我想我最終可能會遇到這個問題。我目前的結論是,難度是由response.body_as_unicode
上執行r.match
造成的。提供的文檔here說匹配:
If zero or more characters at the beginning of string match the regular expression pattern, return a corresponding MatchObject instance. Return None if the string does not match the pattern; note that this is different from a zero-length match.
Note that even in MULTILINE mode, re.match() will only match at the beginning of the string and not at the beginning of each line.
這種行爲不適合我的情況。我很感興趣從包含我的關鍵字的網頁中識別和抓取信息,而不是那些將我的關鍵字之一作爲頁面上的第一項的信息。爲了完成這個任務,我需要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()
感謝您的回覆!打開的文件 - >在文件方式中讀取單詞遠不如我想象中的那樣迂迴。但是,我的措辭最初不精確;我不想檢查是否存在關鍵字,將其中至少有一個作爲我解析的條件。這個破碎的代碼可能會給我一個更清晰的圖像,我打算: 與開放('keys.txt')作爲keyword_list: 如果response.xpath('// * [文本()[包含(。 ,字在keyword_list)]]'): – Tric
@Tric好的,謝謝,更新的版本如何? – alecxe
感謝您的更新。它運行並告訴我我的列表中的單詞是否與response.body匹配;這很好,但它不是我想要的。我想強調一個關鍵字的存在作爲首先抓取數據的條件。我會更新我的原始問題以澄清這一點並提供一些背景。 在附註上,爲什麼定義'source'而不是寫'print any(word.strip()in response.body for word in f)'? – Tric