我想刮一个页面,充满了JavaScript。 url是:
http://www.nasdaqomxnordic.com/index/index_info?Instrument=DK0016268840
我已经使用下面的代码来获取数据。 显然这个代码应该处理的JavaScript和返回一个完整的HTML文件,但它没有。 有可能是一个时间问题,如果是这样,我不是很清楚你在哪里推迟proram允许一个完整的HTML。
import sys 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() def getHtml(str_url): r_html = Render(str_url) html = r_html.frame.toHtml() return html str_url = 'http://www.nasdaqomxnordic.com/index/index_info?Instrument=DK0016268840' str_html = getHtml(str_url) print(str_html)
这给了我,如果你要求网页浏览器页面源,你会得到的HTML。 当然,页面上还有更多的东西,所有的表格都是用javascript函数来填充的。 使用Firebug,我要查找的表的id是“sharesIndexdexable”,我真正想要刮掉的项目是每个公司的名称下的链接 – 但是访问整个表格以使用美丽的expression来parsing会更好。从这张表中,我们应该能够find“嘉士伯”(Carlsberg)这个词(作为一个潜在的testing,看看AJAX是否已经完全加载了)。然后,我试图找出parsingDOM的东西,我尝试了这个:
import sys from PyQt4 import QtGui, QtCore, QtWebKit class Sp(): def printit(self): data = self.webView.page().mainFrame().findFirstElement('id="sharesInIndexTable"') print(data) def main(self): self.webView = QtWebKit.QWebView() self.webView.load(QtCore.QUrl("http://www.nasdaqomxnordic.com/index/index_info?Instrument=DK0016268840")) QtCore.QObject.connect(self.webView,QtCore.SIGNAL("loadFinished(bool)"),self.printit) app = QtGui.QApplication(sys.argv) s = Sp() s.main() sys.exit(app.exec_())
我从这里得到的是PyQt4.QtWebkit.QWebElement对象在0x03294830(你的结果可能会有所不同)。 无论我试图把这个地址变成可读的格式,都失败了。 这段代码似乎也运行了两次。 然后我尝试了这个(有点适应我的需要):
#!/usr/bin/python # These lines will get us the modules we need. from PyQt4.QtCore import QUrl, SIGNAL from PyQt4.QtGui import QApplication from PyQt4.QtWebKit import QWebPage, QWebView class Scrape(QApplication): def __init__(self): # only work with ["test"] as it normally takes an array of args super(Scrape, self).__init__(["test"]) # Create a QWebView instance and store it. self.webView = QWebView() # Connect our searchform method to the searchform signal of this new # QWebView. self.webView.loadFinished.connect(self.searchForm) def load(self, url): # In the __init__ we stored a QWebView instance into self.webView so # we can load a url into it. It needs a QUrl instance though. self.webView.load(QUrl(url)) def searchForm(self): # We landed here because the load is finished. Now, load the root document # element. It'll be a QWebElement instance. QWebElement is a QT4.6 # addition and it allows easier DOM interaction. documentElement = self.webView.page().currentFrame().documentElement() # Let's find the search input element. print("Begin search") inputSearch = documentElement.findFirst('id="sharesInIndexTable"') # Disconnect ourselves from the signal. self.webView.loadFinished.disconnect(self.searchForm) print("End search") # And connect the next function. self.webView.loadFinished.connect(self.searchResults) def searchResults(self): # As seen above, first grab the root document element and then load all g # classed list items. print("Begin results") results = self.webView.page().currentFrame().documentElement().findAll('td') # Change the resulting QWebElementCollection into a list so we can easily # iterate over it. for e in results.toList(): # Just print the results. print(e.tohtml()) # We are inside a QT application and need to terminate that properly. print("End results") self.exit() # Instantiate our class. my_scrape = Scrape() # Load the Google homepage. my_scrape.load('http://www.nasdaqomxnordic.com/index/index_info?Instrument=DK0016268840') # Start the QT event loop. my_scrape.exec_()
我添加了print()语句来确定程序是否完全执行了这些命令。 这完全没有产生(除了印刷报表)
检查源页面,我可以find填充表格的脚本:
var sharesInIndex = { load: function () { var index = webCore.getInstrument(); var nLabel = 'nm'; var hiddenAttributes = ",lists,tp,hlp,isin,note,"; var xslt = "inst_table.xsl"; var options = ",noflag,sectoridicon,"; var xpath = "//index//instruments"; // Check if swedish r nteindex or Icelandic r nteindex. if ( index.indexOf('OMFSE') >= 0 || webCore.getInstrument().indexOf('IS00000') >= 0 ) { hiddenAttributes += ",to,sectid,"; nLabel = 'fnm'; } // Check if weights index present (typeof) var shbindex = ",SE0002834820,SE0002834838,SE0002834846,SE0002977397,"; if ( shbindex.indexOf(index) >= 0 ) { xslt = "inst_table_windex.xsl"; options += "windex,"; xpath = "//index"; } var query = webCore.createQuery( Utils.Constants.marketAction.getIndexInstrument, { inst__a: "0,1,2,5,37,4,20,21,23,24,33,34,97,129,98,10", /* 87,*/ Instrument: index, XPath: xpath, ext_xslt: xslt, ext_xslt_lang: currentLanguage, ext_xslt_tableId: "sharesInIndexTable", ext_xslt_hiddenattrs: hiddenAttributes, ext_xslt_notlabel: nLabel, ext_xslt_options: options }); $("#sharesInIndexOutput").empty().loading("/static/nordic/css/img/loading.gif"); $("#sharesInIndexOutput").load( webCore.getProxyURL('prod'), {xmlquery: query}, function( responseText, textStatus, XMLHttpRequest) { $("#sharesInIndexTable").tablesorter({ widgets: ['zebra'], textExtraction: 'complex', numberFormat: Utils.Constants.numberFormat[currentLanguage] }); $("#sharesInIndexTable a").each( function() { $(this).attr("href",webCore.getURL( Utils.Constants.pages.micrositeShare, $(this).attr('name') )); }); }); } }; $(document).ready( sharesInIndex.load );
我知道有一个“execute_script”命令,但我不知道如何实现它,也没有发现任何适合的例子 – 我不介意如果结果是JSON或HTML或纯文本。 我相信这是答案的地方:(1)加载页面,(2)运行页面脚本,(3)得到结果,(4)parsing/打印/保存结果…
如果有的话,我最好有一个无头解决scheme,甚至窗口上的Phantomjs也不是完全没有头脑,因为它popup一个cmd窗口(我知道你可以用Linux上的虚拟显示器来摆脱这个问题 – 但这不是环境)。 另外,只要告诉我:哦,你必须轮询它,看看数据是否加载,然后你检索它是不是很有帮助:你能告诉我(即使在伪代码)如何进行民意测验,更重要的是大致在哪里程序是否轮询发生(这就是为什么我张贴完整的可执行代码 – 如果别人有同样的问题,他们应该有一个完整的和易于理解的答案)。
我最近的尝试(1 – 插入延迟,以允许AJAX加载)
import sys from PyQt4.QtGui import * from PyQt4.QtCore import * from PyQt4.QtWebKit import * import time class Render(QWebPage): def __init__(self, url): self.app = QApplication(sys.argv) QWebPage.__init__(self) self.mainFrame().load(QUrl(url)) self.loadFinished.connect(self._loadFinished) self.app.exec_() def _loadFinished(self, result): time.sleep(5) self.frame = self.currentFrame() self.app.quit() url = 'http://www.nasdaqomxnordic.com/index/index_info?Instrument=DK0016268840' r = Render(url) html = r.frame.toHtml() print(html)
(2 – 轮询源页面中已知的项目) – 使用萤火虫检查器发现的项目 – 可能findFirst的参数的语法是错误的。
import sys from PyQt4.QtGui import * from PyQt4.QtCore import * from PyQt4.QtWebKit import * import time class Render(QWebPage): def __init__(self, url): self.app = QApplication(sys.argv) QWebPage.__init__(self) self.mainFrame().load(QUrl(url)) self.loadFinished.connect(self._loadFinished) self.app.exec_() def _loadFinished(self, result): counter = 0 while(self.mainFrame().documentElement().findFirst("id=sharesInIndexTable")): counter+=1 print(counter) time.sleep(1) self.frame = self.currentFrame() self.app.quit() url = 'http://www.nasdaqomxnordic.com/index/index_info?Instrument=DK0016268840' r = Render(url) html = r.frame.toHtml() print(html)
这最后一个有一个柜台,显示是否有事情发生。 它永远计数,必须用ctrl-c来停止。
(3 – 使用WebElement的另一个变体)
import sys from PyQt4.QtGui import * from PyQt4.QtCore import * from PyQt4.QtWebKit import * import time class Render(QWebPage): def __init__(self, url): self.app = QApplication(sys.argv) QWebPage.__init__(self) self.mainFrame().load(QUrl(url)) self.loadFinished.connect(self._loadFinished) self.app.exec_() def _loadFinished(self, result): table = self.mainFrame().documentElement().findFirst("id=sharesInIndexTable") print(table) #prints: <PyQt4.QtWebKit.QWebElement object at 0x0319FB0> print("Attributes:") print(table.attributeNames()) #prints: [] ie None print("Classes: ") print(table.classes()) #prints: [] ie None print("InnerXML: " + table.toInnerXml()) #prints nothing print("OuterXML: " + table.toOuterXml()) #prints nothing print("Done") self.frame = self.currentFrame() self.app.quit() url = 'http://www.nasdaqomxnordic.com/index/index_info?Instrument=DK0016268840' r = Render(url) html = r.frame.toHtml()
这个没有成功。 我把代码打印出来。 那里显然有一个对象,但是我看不到里面有什么东西。
我知道这已经很长时间了,但是这个答案对于后来的访问者来说也是类似的情况
我碰到类似的问题,我尝试了各种各样的东西,如等待从QWebPage loadFinished以及QWebFrame,从QWebFrame.intialLayoutCompleted()等信号等信号。
终于为我工作的事情是这样的:
我只是在一个正常的浏览器中提交页面。 检查了由于JavaScript而没有在PyQt中渲染的元素,得到了该元素的id(如果它是一个div,反过来包含多个元素,表等,然后得到div ID)。 现在在yourPage.loadFinished函数中的python代码中调用yourFrame.evaluateJavaScript(“document.getElementById(element_id_retrieved_earlier')”)。
这将等待id被检索,这又将等待嵌入的脚本被执行。