python爬虫进阶(二):动态网页爬取

一、分析动态网页


1、分析工具

用Beyond Compare分析网页是否含有动态部分。


2、直接python解析判断

找到你锁需的内容,用常规方式爬取测验,如果不能爬取,则应该考虑是否有动态网页了!!


二、常用方案


1、找到JS文件

我之前已经掌握一种方案,找到动态网页的js文件,而且还非常简单,但是美中不足的是要找到加载出来的js文件,并找到这些动态页面的规律,这里需要靠人为查找。


推荐教程:Python爬取js动态页面


2、python web 引擎


安装:

selenium 的安装很简单:

pip install selenium


phantomjs的安装有点复杂:

先下载安装nodejs,很简单。


如果需要用浏览器显示还要安装对应的浏览器driver:

查看chromedriver教程


selenium + chrome/phantomjs教程

直接代码,代码中有详细解释,没解释到的后文会给出解释:

import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from pyquery import PyQuery as pq
import pymongo

client = pymongo.MongoClient('localhost')
db = client['tbmeishi']

driver = webdriver.PhantomJS(service_args=['--ignore-ssl-errors=true','--load-images=false','--disk-cache=true'])
driver.set_window_size(1280,2400)       #当无浏览器界面时必须设置窗口大小
#driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)

def search():
    try:
        driver.get('https://www.taobao.com/')       #加载淘宝首页
        #等待页面加载出输入框
        input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#q")))
        #等待页面出现搜索按钮
        submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#J_TSearchForm > div.search-button > button")))
        input.send_keys('美食')       #向输入框中输入‘美食’关键字
        submit.click()                  #点击搜索按钮
        #等待页面加载完
        total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.total')))
        #第一页加载完后,获取第一页信息
        get_products()
        return total.text
    except TimeoutException:
        return search()

def next_page(page_number):
    try:
        # 等待页面出现搜索按钮
        submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > ul > li.item.next > a")))
        submit.click()  # 点击确定按钮
        #判断当前页面是否为输入页面
        wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_number)))
        #第i页加载完后,获取页面信息
        get_products()
    except TimeoutException:
        return next_page(page_number)

def get_products():
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
    html = driver.page_source
    doc = pq(html)
    items = doc('#mainsrp-itemlist .items .item').items()
    for item in items:
        product = {
            'image': item.find('.pic .img').attr('src'),
            'price': item.find('.price').text(),
            'deal': item.find('.deal-cnt').text()[:-3],
            'title': item.find('.title').text(),
            'shop': item.find('.shop').text(),
            'location': item.find('.location').text()
        }
        print(product)
        #save_to_mongo(product)

def save_to_mongo(result):
    try:
        if db['product'].insert(result):
            print('存储到MONGODB成功', result)
    except Exception:
        print('存储到MONGODB失败', result)


def main():
    try:
        total = search()
        total = int(re.compile('(\d+)').search(total).group(1))
        for i in range(2,total+1):
            print('第 %d 页'%i)
            next_page(i)
            
    except Exception as e:
        print('error!!!',e)
    finally:
        driver.close()

if __name__ == '__main__':
    main()
    


在做selenium时最好参考 selenium for Python API  ,里面有很多用法。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

当用无界面操作时,必须注意设置窗口大小,并且尽量设置大一点,如果这个尺寸设置得比较小,我们就不得用JavaScript的scroll命令来模拟页面往下滑动的效果以显示更多内容,所以设置一个比较大的窗口来渲染

driver.set_window_size(1280,2400)

selenium实现了一些类似xpath的功能,可以用driver直接获取我们想要的元素,直接调用下列方法:


但这种方法速度太慢,我们一般不采用,而是将driver直接获取网页源码:html = driver.page_source ,然后用lxml + xpath或BeautifulSoup对其解析;


除此之外还可以用另一种方法解析:pyquery

参考这两篇博文:

http://cuiqingcai.com/2636.html

http://blog.csdn.net/cnmilan/article/details/8727308

下面这段代码就是用pyquery方法解析的,真的很简单。

def get_products():
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
    html = driver.page_source
    doc = pq(html)
    items = doc('#mainsrp-itemlist .items .item').items()
    for item in items:
        product = {
            'image': item.find('.pic .img').attr('src'),
            'price': item.find('.price').text(),
            'deal': item.find('.deal-cnt').text()[:-3],
            'title': item.find('.title').text(),
            'shop': item.find('.shop').text(),
            'location': item.find('.location').text()
        }
        print(product)


selenium还包括很多方法:



注意:

在运行结束后一定要调用driver.close()或driver.quit()来退出phantomjs,不然phantomjs会一直占有内存资源。

建议用driver.service.process.send_signal(signal.SIGTERM)


可以强制kill,Windows下百度

Linux下:

ps aux | grep phantomjs  #查看phantomjs进程

pgrep phantomjs | xargs kill   #kill全部phantomjs


PhantomJS配置

driver = webdriver.PhantomJS(service_args=['--ignore-ssl-errors=true','--load-images=false','--disk-cache=true'])

--ignore-ssl-errors = [true|false] #是否检查CA证书、安全

--load-images = [true|false] #是否加载图片,一般不加载,节约时间

--disk-cache = [true|false] #是否缓存




最后,总结一下,常规爬取方法操作更简单,尤其是用selenium的一些方法的时候,初学者感到很困难;而且,用selenium+phantomjs方法会慢一些,应为这个相当于是一个人在访问网页,会需要等待加载时间,而常规爬取方法是直接拿网页代码,会快一些。当然,有点时候selenium+phantomjs会简单很多,它是假装一个人在访问,反爬虫也不易发现,而且有些网页有陷阱,传统方法会很麻烦,对于慢的问题,可以用多线程解决。


总而言之,case by case !!!!



你可能感兴趣的:(python)