簡體   English   中英

PyQt4 Scrapy實施

[英]PyQt4 Scrapy Implementation

使用scrapy我遇到了用javascript渲染頁面的問題。 例如,對於Forum Franchise網站的鏈接http://www.idee-franchise.com/forum/viewtopic.php?f=3&t=69 ,嘗試抓取源html我找不到任何帖子,因為它們似乎呈現頁面后“附加”(可能通過javascript)。

所以我在網上尋找解決此問題的方法,結果遇到了https://impythonist.wordpress.com/2015/01/06/ultimate-guide-for-scraping-javascript-rendered-web-pages/

我是PYPQ的新手,但希望能走捷徑並復制粘貼一些代碼。

當我嘗試抓取單個頁面時,這非常適合。 但是當我在草率地實現這一點時,出現以下錯誤:

QObject::connect: Cannot connect (null)::configurationAdded(QNetworkConfiguration) to QNetworkConfigurationManager::configurationAdded(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationRemoved(QNetworkConfiguration) to QNetworkConfigurationManager::configurationRemoved(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationChanged(QNetworkConfiguration) to QNetworkConfigurationManager::configurationChanged(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::onlineStateChanged(bool) to QNetworkConfigurationManager::onlineStateChanged(bool)
QObject::connect: Cannot connect (null)::configurationUpdateComplete() to QNetworkConfigurationManager::updateCompleted()

如果我只抓取一個頁面,則不會發生任何錯誤,但是當我將爬蟲設置為遞歸模式時,則在第二個鏈接處我會收到一個錯誤,指出python.exe停止工作,並且出現了以上錯誤。

我將搜索可能是什么,並且在某個地方讀取QApplication對象應該只啟動一次。

有人可以告訴我正確的實現方法是什么?

蜘蛛

# -*- coding: utf-8 -*-
import scrapy
import sys, traceback
from bs4 import BeautifulSoup as bs
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from crawler.items import ThreadItem, PostItem
from crawler.utils import utils


class IdeefranchiseSpider(CrawlSpider):
    name = "ideefranchise"
    allowed_domains = ["idee-franchise.com"]
    start_urls = (
        'http://www.idee-franchise.com/forum/',
        # 'http://www.idee-franchise.com/forum/viewtopic.php?f=3&t=69',
    )

    rules = [
        Rule(LinkExtractor(allow='/forum/'), callback='parse_thread', follow=True)
    ]

    def parse_thread(self, response):
        print "Parsing Thread", response.url
        thread = ThreadItem()
        thread['url'] = response.url
        thread['domain'] = self.allowed_domains[0]
        thread['title'] = self.get_thread_title(response)
        thread['forumname'] = self.get_thread_forum_name(response)
        thread['posts'] = self.get_thread_posts(response)
        yield thread

        # paginate if possible
        next_page = response.css('fieldset.display-options > a::attr("href")')
        if next_page:
            url = response.urljoin(next_page[0].extract())
            yield scrapy.Request(url, self.parse_thread)

    def get_thread_posts(self, response):
        # using PYQTRenderor to reload page. I think this is where the problem
        # occurs, when i initiate the PYQTPageRenderor object. 
        soup = bs(unicode(utils.PYQTPageRenderor(response.url).get_html()))

        # sleep so that PYQT can render page
        # time.sleep(5)

        # comments
        posts = []
        for item in soup.select("div.post.bg2") + soup.select("div.post.bg1"):
            try:
                post = PostItem()
                post['profile'] = item.select("p.author > strong > a")[0].get_text()
                details = item.select('dl.postprofile > dd')
                post['date'] = details[2].get_text()
                post['content'] = item.select('div.content')[0].get_text()

                # appending the comment
                posts.append(post)
            except:
                e = sys.exc_info()[0]
                self.logger.critical("ERROR GET_THREAD_POSTS %s", e)
                traceback.print_exc(file=sys.stdout)
        return posts

PYPQ實施

import sys
from PyQt4.QtCore import QUrl
from PyQt4.QtGui import QApplication
from PyQt4.QtWebKit import QWebPage 

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()


class PYQTPageRenderor(object):
    def __init__(self, url):
        self.url = url

    def get_html(self):
        r = Render(self.url)
        return unicode(r.frame.toHtml())

如果您想自己做,正確的實現是創建一個使用PyQt處理請求的下層中間件 Scrapy將實例化它一次。

不應該那么復雜,只是

  1. 在項目的middleware.py文件中創建QTDownloader類

  2. 構造函數應創建QApplication對象。

  3. process_request方法應該執行url加載和HTML提取。 請注意,您將返回帶有HTML字符串的Response對象。

  4. 您可以在類的_cleanup方法中進行適當的清理。

  5. 最后,通過將中間件添加到項目的settings.py文件的DOWNLOADER_MIDDLEWARES變量中來激活它。

如果您不想編寫自己的解決方案,則可以使用使用Selenium進行下載的現有中間件,例如scrapy-webdriver 如果您不想使用可見的瀏覽器,則可以指示它使用PhantomJS。

EDIT1:因此,如Rejected所指出的,執行此操作的正確方法是使用下載處理程序。 這個想法是相似的,但是下載應該以download_request方法進行,並且應該通過將其添加到DOWNLOAD_HANDLERS來啟用。 WebdriverDownloadHandler為例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM