使用Selenium获取网页上的所有可见文本

13 投票
2 回答
19822 浏览
提问于 2025-04-17 05:18

我今天一直在网上查这个问题,但没找到答案,所以如果这个问题已经有人回答过,我先说声抱歉。

我想从很多不同的网站上获取所有可见的文本。这样做的原因是我想处理这些文本,最终对这些网站进行分类。

经过几天的研究,我决定使用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和Beautiful Soup,是因为我想抓取经过JavaScript处理的文本。

2 个回答

5

这是对 @unutbu的回答 的一种变体:

#!/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://stackoverflow.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生成的元素)
  • 提取文本

这段代码之间的连接仅通过缓存来实现。你可以在一个过程中获取网页,然后在另一个过程中提取文本,或者可以选择稍后再用不同的方法来完成这项工作。

10

使用 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动态生成的,或者是通过刷新页面来更新的)。

撰写回答