抓取动态网页(如何从javascript页面爬取信息中进行数据爬取?(一))
优采云 发布时间: 2021-09-17 21:00抓取动态网页(如何从javascript页面爬取信息中进行数据爬取?(一))
一、simple动态页面爬行
我们以前的页面爬行工作是基于静态页面的。但是现在很多页面使用动态页面,其中70%的动态页面是由JavaScript编写的。因此,了解如何从JavaScript页面抓取信息对我们来说非常重要
在了解具体情况之前,我们需要了解AJAX是什么。它的英文全称是AsynchronousJavaScript和XML,它是一种异步JavaScript和XML。我们可以通过Ajax请求页面数据,返回的数据格式是JSON类型
然后我们可以根据页面的Ajax格式抓取数据。下面是一个简单的页面爬网
import json
from Chapter3 import download
import csv
def simpletest():
'''
it will write the date to the country.csv
the json data has the attribute records, and the records has area, country and capital value
:return:
'''
fileds = ('area', 'country', 'capital')
writer = csv.writer(open("country.csv", "w"))
writer.writerow(fileds)
d = download.Downloader()
html = d("http://example.webscraping.com/ajax/search.json?page=0&page_size=10&search_term=A")
try:
ajax = json.loads(html)
except Exception as e:
print str(e)
else:
for record in ajax['records']:
row = [record[filed] for filed in fileds]
writer.writerow(row)
if __name__ == "__main__":
simpletest()
我不知道这是否是问题所在。现在我无法从上述网站下载数据。执行上述程序。以下是结果图:
二、呈现动态页面
在开始之前,首先下载pyside并直接使用PIP install pyside命令行
然后我们可以使用pyside来抓取数据
from PySide.QtWebKit import *
from PySide.QtGui import *
from PySide.QtCore import *
import lxml.html
def simpletest():
'''
get content of the div # result in http://example.webscraping.com/places/default/dynamic
:return: content
'''
app = QApplication([])
webview = QWebView()
loop = QEventLoop()
# finish the loop if we have finished load the html
webview.loadFinished.connect(loop.quit)
webview.load(QUrl("http://example.webscraping.com/places/default/dynamic"))
loop.exec_()
htmled = webview.page().mainFrame().toHtml()
# get the special content
tree = lxml.html.fromstring(htmled)
return tree.cssselect('#result')[0].text_content()
content = simpletest()
print content
我们回顾了简单动态页面爬行的内容。以前的方法不成功。我认为主要原因是我的网站写得不正确,所以在学习pyside之后,我们可以使用这种新方法进行数据爬行。以下是具体代码:
def getallcountry():
'''
open the html and set search term = a and page_size = 10
and then click auto by javascript
:return:
'''
app = QApplication([])
webview = QWebView()
loop = QEventLoop()
# finish the loop if we have finished load the html
webview.loadFinished.connect(loop.quit)
webview.load(QUrl("http://example.webscraping.com/places/default/search"))
loop.exec_()
# show the webview
webview.show()
frame = webview.page().mainFrame()
# set search text is b
frame.findFirstElement('#search_term').setAttribute('value', 'b')
# set page_size is 10
frame.findFirstElement('#page_size option:checked').setPlainText('10')
# click search button auto
frame.findFirstElement('#search').evaluateJavaScript('this.click()')
app.exec_()
以下是结果图:
在上面的过程中,我们只使用pyside在页面上获取结果,但还没有对数据进行爬网。因为Ajax在响应事件时有一定的延迟,所以有三种方法可以抓取数据:
1、等待一定时间(效率低下)
2、rewrite QT的网络管理器,以跟踪URL请求的完成时间(不适用于客户端问题的情况)
3、轮询页面并等待特定内容出现(检查时浪费CPU时间)
一般来说,第三种方法更可靠、更方便。下面是它的概念代码:它的主要思想是while循环。如果找不到元素,请继续尝试
为了使上述方法更通用,我们可以将它们编写在一个类中。此类收录以下功能:下载、获取HTML、查找对应元素、设置属性值、设置文本值、单击、轮询页面并等待下载
<p>from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtWebKit import *
import time
import sys
class BrowserRender(QWebView):
def __init__(self, show=True):
'''
if the show is true then we can see webview
:param show:
'''
self.app = QApplication(sys.argv)
QWebView.__init__(self)
if show:
self.show()
def download(self, url, timeout=60):
'''
download the url if timeout is false
:param url: the download url
:param timeout: the timeout time
:return: html if not timeout
'''
loop = QEventLoop()
timer = QTimer()
timer.setSingleShot(True)
timer.timeout.connect(loop.quit)
self.loadFinished.connect(loop.quit)
self.load(QUrl(url))
timer.start(timeout*1000)
loop.exec_()
if timer.isActive():
timer.stop()
return self.html()
else:
print "Request time out "+url
def html(self):
'''
shortcut to return the current html
:return:
'''
return self.page().mainFrame().toHtml()
def find(self, pattern):
'''
find all elements that match the pattern
:param pattern:
:return:
'''
return self.page().mainFrame().findAllElements(pattern)
def attr(self, pattern, name, value):
'''
set attribute for matching pattern
:param pattern:
:param name:
:param value:
:return:
'''
for e in self.find(pattern):
e.setAttribute(name, value)
def text(self, pattern, value):
'''
set plaintext for matching pattern
:param pattern:
:param value:
:return:
'''
for e in self.find(pattern):
e.setPlainText(value)
def click(self, pattern):
'''
click matching pattern
:param pattern:
:return:
'''
for e in self.find(pattern):
e.evaluateJavaScript("this.click()")
def wait_load(self, pattern, timeout=60):
'''
wait untill pattern is found and return matches
:param pattern:
:param timeout:
:return:
'''
deadtiem = time.time() + timeout
while time.time()