【问题标题】:Tried Python BeautifulSoup and Phantom JS: STILL can't scrape websites尝试过 Python BeautifulSoup 和 Phantom JS:仍然无法抓取网站
【发布时间】:2014-03-28 12:52:40
【问题描述】:

您可能已经在这里看到了过去几周我绝望的挫败感。我一直在抓取一些等待时间数据,但仍然无法从这两个站点获取数据

http://www.centura.org/erwait

http://hcavirginia.com/home/

起初我尝试了 BS4 for Python。下面是 HCA Virgina 的示例代码

from BeautifulSoup import BeautifulSoup
import requests

url = 'http://hcavirginia.com/home/'
r = requests.get(url)

soup = BeautifulSoup(r.text)
wait_times = [span.text for span in soup.findAll('span', attrs={'class': 'ehc-er-digits'})]

fd = open('HCA_Virginia.csv', 'a')

for w in wait_times:
    fd.write(w + '\n')

fd.close()

所有这些都是在控制台或 CSV 中打印空白。所以我用 PhantomJS 试了一下,因为有人告诉我它可能是用 JS 加载的。然而,同样的结果!将空白打印到控制台或 CSV。下面的示例代码。

var page = require('webpage').create(),
url = 'http://hcavirginia.com/home/';

page.open(url, function(status) {
if (status !== "success") {
    console.log("Can't access network");
} else {
    var result = page.evaluate(function() {

        var list = document.querySelectorAll('span.ehc-er-digits'), time = [], i;
        for (i = 0; i < list.length; i++) {
            time.push(list[i].innerText);
        }
        return time;

    });
    console.log (result.join('\n'));
    var fs = require('fs');
    try 
    {                   
        fs.write("HCA_Virginia.csv", '\n' + result.join('\n'), 'a');
    } 
    catch(e) 
    {
        console.log(e); 
    } 
}

phantom.exit();
});

Centura Health 存在同样的问题 :(

我做错了什么?

【问题讨论】:

  • 试试ghost.py - 它应该为你加载所有的JS。虽然速度可能有点慢,但我会建议你检查一下。 (免责声明:我还没有检查你的代码)
  • 似乎ghost.py 有很多错误 - 上次它对我有用,但现在我的测试脚本因错误退出......:/
  • 我认为这可能是页面的某种负载问题?我已经在许多其他网站上成功使用了 BS4 和 Phantom。这些网站把它扔掉......

标签: javascript python web-scraping beautifulsoup phantomjs


【解决方案1】:

您面临的问题是元素是由 JS 创建的,加载它们可能需要一些时间。你需要一个处理 JS 的爬虫,并且可以等到创建所需的元素。

您可以使用PyQt4。适配this recipe from webscraping.com 和像BeautifulSoup 这样的HTML 解析器,这很容易:

(写完之后,我找到了python的webscraping库。可能值得一看)

import sys
from bs4 import BeautifulSoup
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtWebKit import * 

class Render(QWebPage):
    def __init__(self, url):
        self.app = QApplication(sys.argv)
        QWebPage.__init__(self)
        self.loadFinished.connect(self._loadFinished)
        self.mainFrame().load(QUrl(url))
        self.app.exec_()

    def _loadFinished(self, result):
        self.frame = self.mainFrame()
        self.app.quit()   

url = 'http://hcavirginia.com/home/'
r = Render(url)
soup = BeautifulSoup(unicode(r.frame.toHtml()))
# In Python 3.x, don't unicode the output from .toHtml(): 
#soup = BeautifulSoup(r.frame.toHtml()) 
nums = [int(span) for span in soup.find_all('span', class_='ehc-er-digits')]
print nums

输出:

[21, 23, 47, 11, 10, 8, 68, 56, 19, 15, 7]

这是我原来的答案,使用 ghost.py:

我设法使用ghost.py 为你破解了一些东西。 (在 Python 2.7、ghost.py 0.1b3 和 PyQt4-4 32-bit 上测试)。我不建议在生产代码中使用它!

from ghost import Ghost
from time import sleep

ghost = Ghost(wait_timeout=50, download_images=False)
page, extra_resources = ghost.open('http://hcavirginia.com/home/',
                                   headers={'User-Agent': 'Mozilla/4.0'})

# Halt execution of the script until a span.ehc-er-digits is found in 
# the document
page, resources = ghost.wait_for_selector("span.ehc-er-digits")

# It should be possible to simply evaluate
# "document.getElementsByClassName('ehc-er-digits');" and extract the data from
# the returned dictionary, but I didn't quite understand the
# data structure - hence this inline javascript.
nums, resources = ghost.evaluate(
    """
    elems = document.getElementsByClassName('ehc-er-digits');
    nums = []
    for (i = 0; i < elems.length; ++i) {
        nums[i] = elems[i].innerHTML;
    }
    nums;
    """)

wt_data = [int(x) for x in nums]
print wt_data
sleep(30) # Sleep a while to avoid the crashing of the script. Weird issue!

一些cmets:

  • 正如您从我的 cmets 中看到的,我并没有完全弄清楚从 Ghost.evaluate(document.getElementsByClassName('ehc-er-digits');) 返回的 dict 的结构 - 不过,使用这样的查询可能会找到所需的信息。

  • 我也遇到了一些脚本在最后崩溃的问题。睡眠 30 秒解决了这个问题。

【讨论】:

  • 我已经投了赞成票,但我需要 15 点声望才能做到这一点。谢谢!
  • 谢谢!我必须对pyQt4 答案进行的唯一更改是将soup = BeautifulSoup(unicode(r.frame.toHtml())) 更改为soup = BeautifulSoup(r.frame.toHtml())
  • 很酷,@dstudeba!您是否有机会使用 Python 3.X?我已经有一段时间没有使用 BS 了,但是 unicode 在 Python 3 中是标准的,所以我想也没有 unicode 函数:)
  • 是的,我使用的是 Python 3.4,我无法在早期版本的 3 上尝试它,因为我正在使用的另一个包依赖于 3.4。再次感谢!
  • 这就解释了,@dstudeba。我将更新我的答案,以帮助希望在 Python 3 环境中应用此解决方案的未来读者。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
相关资源
最近更新 更多