使用 Selenium 从网页中获取所有可见文本
Posted
技术标签:
【中文标题】使用 Selenium 从网页中获取所有可见文本【英文标题】:Getting all visible text from a webpage using Selenium 【发布时间】:2011-12-18 08:31:01 【问题描述】:我整天都在谷歌上搜索这个问题,但没有找到答案,所以如果这个问题已经得到解答,请提前道歉。
我正在尝试从大量不同的网站获取所有可见文本。原因是我想处理文本以最终对网站进行分类。
经过几天的研究,我认为 Selenium 是我最好的机会。我找到了一种使用 Selenium 抓取所有文本的方法,不幸的是,同一文本被多次抓取:
from selenium import webdriver
import codecs
filen = codecs.open('outoput.txt', encoding='utf-8', mode='w+')
driver = webdriver.Firefox()
driver.get("http://www.examplepage.com")
allelements = driver.find_elements_by_xpath("//*")
ferdigtxt = []
for i in allelements:
if i.text in ferdigtxt:
pass
else:
ferdigtxt.append(i.text)
filen.writelines(i.text)
filen.close()
driver.quit()
for
循环内的if
条件试图消除多次获取相同文本的问题 - 但是,它不能按计划在某些网页上工作。 (这也让脚本慢了很多)
我猜我的问题的原因是 - 在询问元素的内部文本时 - 我还得到了嵌套在相关元素内的元素的内部文本。
有没有办法解决这个问题?是否有某种主元素我抓住了内部文本?或者完全不同的方式可以让我达到我的目标?任何帮助将不胜感激,因为我对此一无所知。
编辑:我使用 Selenium 而不是 Mechanize and Beautiful Soup 的原因是因为我想要 javascript 提供的文本
【问题讨论】:
lynx
和 w3c
都可以通过 CLI 执行此操作。
你的 xpath 不应该是 //body/text()
之类的吗?
您的代码似乎有明显的错误:for i in allelements: if i.allelements in ferdigtxt: pass
如果i
在allelements
中,那么i.allelements
可能是一个错误。
另一个观察结果是,您似乎在比较它们之间的整个文本节点,并且在几乎 100% 的情况下,这种比较可能是错误的。如果您真的想比较使用的单词,那么@unutbu 的解决方案提供了这一点。请编辑您的问题并明确定义问题。
@Blender:lynx
和 w3c
支持 JavaScript 吗? (我对此表示怀疑)。
【参考方案1】:
使用lxml,您可以尝试以下操作:
import contextlib
import selenium.webdriver as webdriver
import lxml.html as LH
import lxml.html.clean as clean
url="http://www.yahoo.com"
ignore_tags=('script','noscript','style')
with contextlib.closing(webdriver.Firefox()) as browser:
browser.get(url) # Load page
content=browser.page_source
cleaner=clean.Cleaner()
content=cleaner.clean_html(content)
with open('/tmp/source.html','w') as f:
f.write(content.encode('utf-8'))
doc=LH.fromstring(content)
with open('/tmp/result.txt','w') as f:
for elt in doc.iterdescendants():
if elt.tag in ignore_tags: continue
text=elt.text or ''
tail=elt.tail or ''
words=' '.join((text,tail)).strip()
if words:
words=words.encode('utf-8')
f.write(words+'\n')
这似乎可以获取 www.yahoo.com 上的几乎所有文本,除了图像中的文本和一些随时间变化的文本(可能使用 javascript 和刷新完成)。
【讨论】:
非常感谢 unutbu 的彻底回答!您使用了很多我不熟悉的代码,因此将退出阅读您的解决方案。很抱歉,我之前没有指定这一点 - 但我使用 selenium 的原因是为了确保我可以获得 javascript 呈现的文本 - 据我了解,您的解决方案不提供该功能。话虽如此,如果我找不到同时获取 html 和 javascript 呈现的文本的方法,我肯定会尝试您的解决方案。所以再次感谢你! 上面贴出的代码使用了 Selenium 的 webdriver,所以它会包含 javascript 渲染的文本。但是,如果您从浏览器访问 yahoo.com,您会在页面顶部看到一个区域,该区域会随着时间或鼠标悬停在某些图像上而发生变化。我注意到上面的代码并没有捕获来自该区域的所有可能的文本。我不确定以编程方式解决此问题的最佳方法(多次重新加载页面?哎呀......)。除此之外,它应该适用于大多数网站。 哇,太棒了!非常感谢 unutbu - 我一开始工作就会深入研究你的代码 :)【参考方案2】:这是@unutbu's answer 的变体:
#!/usr/bin/env python
import sys
from contextlib import closing
import lxml.html as html # pip install 'lxml>=2.3.1'
from lxml.html.clean import Cleaner
from selenium.webdriver import Firefox # pip install selenium
from werkzeug.contrib.cache import FileSystemCache # pip install werkzeug
cache = FileSystemCache('.cachedir', threshold=100000)
url = sys.argv[1] if len(sys.argv) > 1 else "https://***.com/q/7947579"
# get page
page_source = cache.get(url)
if page_source is None:
# use firefox to get page with javascript generated content
with closing(Firefox()) as browser:
browser.get(url)
page_source = browser.page_source
cache.set(url, page_source, timeout=60*60*24*7) # week in seconds
# extract text
root = html.document_fromstring(page_source)
# remove flash, images, <script>,<style>, etc
Cleaner(kill_tags=['noscript'], style=True)(root) # lxml >= 2.3.1
print root.text_content() # extract text
我把你的任务一分为二:
获取页面(包括javascript生成的元素) 提取文本代码仅通过缓存连接。您可以在一个进程中获取页面并在另一个进程中提取文本,或者稍后使用不同的算法进行。
【讨论】:
以上是关于使用 Selenium 从网页中获取所有可见文本的主要内容,如果未能解决你的问题,请参考以下文章