zoukankan      html  css  js  c++  java
  • 爬虫抓取动态内容

    一、简单动态页面爬取

      我们之前进行的页面爬取工作都是基于静态的页面。但是现在的很多页面都采用了动态页面,这些动态页面又有百分之七十是由javascript写的,因此我们了解如何从javascript页面爬取信息就显得非常的重要。

      先认识具体情况之前,我们需要先了解什么是ajax,ajax它的英文全称是asynchronous javascript and 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、重写QT的网络管理器,跟踪url请求的完成时间(不适用于客户端出问题的情况)

      3、轮询页面,等待特定内容出现(检查时会浪费cpu时间)

      总的来说,第三种方法是比较可靠并且方便的。以下是它的概念代码:它的主要思想在于while循环,如果没有找到elements,就不断的尝试。

      

       为了将以上的几种方法变得更加具有通用性,我们可以把他们写在 一个类中。这个类包含的功能有:下载,获取html,找到相应的元素,设置属性值,设置文本值,点击,轮询页面,等待下载

    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() < deadtiem:
                self.app.processEvents()
                matches = self.find(pattern)
                if matches:
                    return matches
            print "wait load timed out"
    
    br = BrowserRender()
    br.download("http://example.webscraping.com/places/default/search")
    br.attr('#search_term', 'value', '.')
    br.text('#page_size option:checked', '1000')
    br.click('#search')
    elements = br.wait_load('#results a')
    countries = [e.toPlainText().strip() for e in elements]
    print countries

      在调用的时候,一定要注意要把pattern写对,我就把#results a 写成了#result a,导致一直出现time out现象

     三、selenium

      selenium 是一个简单的能够与页面交互的接口,它提供了使得浏览器自动化的API接口。selenium的使用非常的简单,它相当于已经把我们想要的函数都已经封装起来了,我们所需要的就是调用相应的函数。

      以下是我们selenium来实现browsrender实现的内容。

    from selenium import webdriver
    def simpleuse():
        driver = webdriver.Chrome()
        driver.get("http://example.webscraping.com/places/default/search")
        driver.find_element_by_id("search_term").send_keys('.')
        js = "document.getElementById('page_size').options[1].text='1000'"
        driver.execute_script(js)
        driver.find_element_by_id('search').click()
        driver.implicitly_wait(30)
        links = driver.find_element_by_css_selector("#results a")
        countries = [link.text for link in links]
        print countries
       driver.close()
    if __name__ == "__main__": simpleuse()

      明明配置了chromedriver,但是它一直显示未在path中找到可执行文件:

      这个问题还没解决,等待后续吧。

      这个问题已经解决了,只需要去官网上下载对应版本的chromedriver.exe,然后将保存它的绝对路径加入 webdriver.chrome(绝对路径)即可。现在的代码变成如下:

    from selenium import webdriver
    def simpleuse():
        driver = webdriver.Chrome('E:chromedriverchromedriver.exe')
        driver.get("http://example.webscraping.com/places/default/search")
        driver.find_element_by_id("search_term").send_keys('.')
        js = "document.getElementById('page_size').options[1].text='1000'"
        driver.execute_script(js)
        driver.find_element_by_id('search').click()
        driver.implicitly_wait(30)
        links = driver.find_elements_by_css_selector("#results a")
        countries = [link.text for link in links]
        print countries
        driver.close()
    
    if __name__ == "__main__":
        simpleuse()

    四、小结

    首先,先采用逆向工程分析页面,然后使用json即可对页面进行解析。然后呢,使用了pyside进行动态页面渲染,最后了为了简便写法使用了selenium。

  • 相关阅读:
    集合
    元组 与 字典
    列表
    练习题
    字符串的类型补充
    3月19号练习题及作业
    变量,用户交互的补充内容,以及数据内容
    Python 入门
    计算机基础
    决策树的概念及其训练
  • 原文地址:https://www.cnblogs.com/whatyouknow123/p/7756842.html
Copyright © 2011-2022 走看看