在网页加载其数据后抓取网页

时间:2015-11-11 22:00:55

标签: python web-scraping

尝试收集学校项目的图书价格波动数据。我使用Python从书籍回购聚合器(在本例中为bookscouter)中删除,但我发现由于网站必须加载数据,因此通过urllib2包获取源代码可以得到源代码在加载数据之前。加载数据后如何从中拉出来?

示例:http://bookscouter.com/prices.php?isbn=9788498383621&searchbutton=Sell

2 个答案:

答案 0 :(得分:1)

挑战是在网络浏览器呈现数据后读取数据,这需要一些额外的技巧。如果您可以查看该网站是否具有预渲染版本 * 或API。

This article (linked from the Web archive)对您需要做的事情有很好的细分。但可以总结如下:

  1. 选择一个好的python-webkit渲染器(在文章PyQT的情况下)
  2. 使用窗口小部件来获取和呈现页面
  3. 从小部件中获取呈现的HTML
  4. 使用像lXML或BeautifulSoup这样的库来正常解析此HTML。
  5. *轻微的咆哮 - 不得不希望预渲染版本的应该是静态网页的想法会让我感到愤怒。

答案 1 :(得分:0)

你不能只使用Python。您需要一个像PhantomJS

这样的JavaScript引擎API

使用Phantom,可以非常轻松地设置Web抓取所有页面内容,静态和动态JavaScript内容(如您的情况下的Ajax调用结果)。事实上,您可以将页面事件处理程序注册到页面解析器(例如node.js + phantom.js示例)

/*
     * Register Page Handlers as functions

    {
        onLoadStarted : onLoadStarted,
        onLoadFinished: onLoadFinished,
        onError : onError,
        onResourceRequested : onResourceRequested,
        onResourceReceived : onResourceReceived,
        onNavigationRequested : onNavigationRequested,
        onResourceError : onResourceError
    }

    */
    registerHandlers : function(page, handlers) {
        if(handlers.onLoadStarted) page.set('onLoadStarted',handlers.onLoadStarted)
        if(handlers.onLoadFinished) page.set('onLoadFinished',handlers.onLoadFinished)
        if(handlers.resourceError) page.set('onResourceError', handlers.resourceError)
        if(handlers.onResourceRequested) page.set('onResourceRequested',handlers.onResourceRequested)
        if(handlers.onResourceReceived) page.set('onResourceReceived',handlers.onResourceReceived)
        if(handlers.onNavigationRequested) page.set('onNavigationRequested',handlers.onNavigationRequested)
        if(handlers.onError) page.set('onError',handlers.onError)

    }

此时您可以完全控制正在进行的操作以及在必须下载的页面中的时间,如:

var onResourceError = function(resourceError) {
                        var errorReason = resourceError.errorString;
                        var errorPageUrl = resourceError.url;
                }
                var onResourceRequested = function (request) {
                    var msg = '  request: ' + JSON.stringify(request, undefined, 4);
                };
                var onResourceReceived = function(response) {
                    var msg = '  id: ' + response.id + ', stage: "' + response.stage + '", response: ' + JSON.stringify(response);
                };
                var onNavigationRequested = function(url, type, willNavigate, main) {
                    var msg = '  destination_url: ' + url;
                    msg += '  type (cause): ' + type;
                    msg += '  will navigate: ' + willNavigate;
                    msg += '  from page\'s main frame: ' + main;
                };
                page.onResourceRequested(
                function(requestData, request) {
                        //request.abort()
                        //request.changeUrl(url)
                        //request.setHeader(key,value)
                        var msg = '  request: ' + JSON.stringify(request, undefined, 4);
                        //console.log( msg )
                    },
                function(requestData) {
                        //console.log(requestData.url)
                })
        PageHelper.registerHandlers(page,
                    {
                        onLoadStarted : onLoadStarted,
                        onLoadFinished: onLoadFinished,
                        onError : null, // onError THIS HANDLER CRASHES PHANTOM-NODE
                        onResourceRequested : null, // MUST BE ON PAGE OBJECT
                        onResourceReceived : onResourceReceived,
                        onNavigationRequested : onNavigationRequested,
                        onResourceError : onResourceError
                    });

如您所见,您可以定义页面处理程序并控制流程以及该页面上加载的资源。因此,在您获取整个页面源之前,您可以确保所有数据都已准备就绪并已设置:

var Parser = {
  parse : function(page) {

    var onSuccess = function (page) { // page loaded
        var pageContents=page.evaluate(function() {
            return document.body.innerText;
        });
      }
    var onError = function (page,elapsed) { // error
    }
    page.evaluate(function(func) {
            return func(document);
        }, function(dom) {
            return true;
        });

  }
} // Parser

在这里,您可以看到onSuccess回调中加载的整个页面内容:

var pageContents=page.evaluate(function() {
                return document.body.innerText;
            });

该页面来自Phantomjs,如下面的代码段所示:

phantom.create(function (ph) {
            ph.createPage(function (page) {
                Parser.parse(page)
            })
        },options)

当然这可以让你了解你可以用node.js + Phantomjs做些什么,它们在组合在一起时非常强大。

您可以在Python环境中运行phantomjs,将其称为

try:
            output = ''
            for result in runProcess([self.runProcess,
            self.runScript,
            self.jobId,
            self.protocol,
            self.hostname,
            self.queryString]):
                output += '' + result
                print output
        except Exception as e:
            print e
            print(traceback.format_exc())

使用子进程Popen执行二进制文件:

def runProcess(exe):
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
      retcode = p.poll() #returns None while subprocess is running
      line = p.stdout.readline()
      yield line
      if(retcode is not None):
        break

当然,在这种情况下运行的进程是node.js

self.runProcess='node'

你需要args作为参数。