python 爬蟲(十)selenium+phantomjs請求頁面流程 + selenium的三種等待 + 案例(豆瓣讀書 + 騰訊招聘)

一、selenium+phantomjs來請頁面的流程


1. 導包


from selenium import webdriver

2. 創建driver對象


driver = webdriver.Phantomjs()

3. 請求url


driver.get(url)

4. 等待


time.sleep(5)

等待有三種:

(1)強制等待:
time.sleep(10)
(2)隱式等待
driver.implicitly_wait(10)
隱式等待就是等到頁面全部加載完成,比如js,css或者圖片全請求到加載到頁面,也就是我們常看到的頁面不在轉圈圈爲止,程序纔會繼續運行。
(3)顯示等待。
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
步驟:
1.創建等待對象
wait = WebDriverWait(
driver,#瀏覽器驅動對象
10,最大等待時長
0.5,掃描間隔
)
2.wait.until(等待條件)—>等待條件成立程序才繼續運行。
等待條件在selenium中有個專門的模塊來設置了一些條件—expected_conditions as EC
最常用的條件有一下兩個:
EC.presence_of_element_located
EC.presence_of_all_elements_located
這兩個條件驗證元素是否出現,傳入的參數都是元組類型的locator,如(By.ID, ‘kw’)
一個只要一個符合條件的元素加載出來就通過;
另一個必須所有符合條件的元素都加載出來才行
EC.presence_of_element_located(locator對象也就是定位器)
licator對象是一個元組(
通過什麼來查找,–By.ID,By.XPATH,By.CSS_SELECTOR
‘查找的內容的語法’)
3.wait.until方法的返回值是一個對應定位器所定位到的webelement對象。你如果需要對這個webelment對象做一些點擊或者其他操作,可以很方便的做到。


4. 獲取頁面內容


html = driver.page_source

5. 用lxml模塊解析頁面內容


tree = etree.HTML(html)

二、selenium的三種等待


1. 強制等待


第一種也是最簡單粗暴的一種辦法就是強制等待sleep(xx),

from selenium import webdriver
from time import sleep
driver = webdriver.Firefox()
driver.get('https://huilansame.github.io')
sleep(3) # 強制等待3秒再執行下一步
print driver.current_url
driver.quit()

這種叫強制等待,不管你瀏覽器是否加載完了,程序都得等待3秒,3秒一到,繼續執行下面的代碼,作爲調試很有用,有時候也可以在代碼裏這樣等待,不過不建議總用這種等待方式,太死板,嚴重影響程序執行速度。


2. 隱性等待


from selenium import webdriver
driver = webdriver.Firefox()
driver.implicitly_wait(30) # 隱性等待,最長等30秒
driver.get('https://huilansame.github.io')
print driver.current_url
driver.quit()

隱形等待是設置了一個最長等待時間,如果在規定時間內網頁加載完成,則執行下一步,否則一直等到時間截止,然後執行下一步。

注意:這裏有一個弊端,那就是程序會一直等待整個頁面加載完成,也就是一般情況下你看到瀏覽器標籤欄那個小圈不再轉,纔會執行下一步,但有時候頁面想要的元素早就在加載完成了,但是因爲個別js之類的東西特別慢,我仍得等到頁面全部完成才能執行下一步,我想等我要的元素出來之後就下一步怎麼辦?有辦法,這就要看selenium提供的另一種等待方式——顯性等待wait了。


3. 顯性等待

第三種辦法就是顯性等待,WebDriverWait,配合該類的until()和until_not()方法,就能夠根據判斷條件而進行靈活地等待了。它主要的意思就是:程序每隔xx秒看一眼,如果條件成立了,則執行下一步,否則繼續等待,直到超過設置的最長時間,然後拋出TimeoutException。
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
#隱性等待和顯性等待可以同時用,但要注意:等待的最長時間取兩者之中的大者
driver.implicitly_wait(10)

driver.get(‘https://huilansame.github.io’)
locator = (By.LINK_TEXT, ‘CSDN’)
try:
wait = WebDriverWait(driver, 20, 0.5)
wait.until(EC.presence_of_element_located(locator))
print(driver.find_element_by_link_text(‘CSDN’).get_attribute(‘href’))
finally:
driver.close()


4. expected_conditions


expected_conditions是selenium的一個模塊,其中包含一系列可用於判斷的條件:

EC.title_is
EC.title_contains
這兩個條件類驗證title,驗證傳入的參數title是否等於或在driver.title中
EC.presence_of_element_located((By.CSS_SELECTOR,'.ui-page > wrap'))
EC.presence_of_all_elements_located((By.CSS_SELECTOR,'.ui-page'))

這兩個條件驗證元素是否出現,傳入的參數都是元組類型的locator,如(By.ID, ‘kw’)
一個只要一個符合條件的元素加載出來就通過;
另一個必須所有符合條件的元素都加載出來才行

EC.visibility_of_element_located
EC.invisibility_of_element_located
EC.visibility_of

這三個條件驗證元素是否可見
前兩個傳入參數是元組類型的locator,第三個傳入WebElement
第一個和第三個其實質是一樣的

EC.text_to_be_present_in_element
EC.text_to_be_present_in_element_value

這兩個判斷某段文本是否出現在某元素中
一個判斷元素的text,一個判斷元素的value屬性

EC.frame_to_be_available_and_switch_to_it

這個條件判斷frame是否可切入,
可傳入locator元組或者直接傳入定位方式:id、name、index或WebElement

#這個條件判斷是否有alert出現
EC.alert_is_present
#這個條件判斷元素是否可點擊,傳入locator
EC.element_to_be_clickable
#這四個條件判斷元素是否被選中,
第一個條件傳入WebElement對象,第二個傳入locator元組
#第三個傳入WebElement對象以及狀態,相等返回True,否則返回False
#第四個傳入locator以及狀態,相等返回True,否則返回False
EC.element_to_be_selected
EC.element_located_to_be_selected
EC.element_selection_state_to_be
EC.element_located_selection_state_to_be
#最後一個條件判斷一個元素是否仍在頁面中,傳入WebElement對象,可以判斷頁面是否刷新
EC.staleness_of

三、案例:豆瓣讀書,騰訊


案例:豆瓣讀書

import json
from urllib import parse
import requests, time
from lxml import etree
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

class Douban:
    def __init__(self,url,kw):
        self.url = url
        self.kw = kw
        self.driver = webdriver.PhantomJS()
        self.info_list = []
        # self.wait = WebDriverWait(self.driver,10)
        self.get_source()


    ## 獲取分頁的每一頁的資源
    def get_source(self):
        ## 分頁
        kw = ''
        for i in range(10):
            params = {'search_text':self.kw,
                        'cat': '1001',
                        'start': str(i*15)
                      }
            self.url = self.url + parse.urlencode(params)
            self.driver.get(self.url)
            ## 等待
            time.sleep(3)
            html_str = self.driver.page_source
            self.parse_page(html_str)

    ## 判空
    def get_text(self,text):
        if text:
            return text[0]
        else:
            return ''
    ## 獲取所需要的信息資源
    def parse_page(self,content):
        html = etree.HTML(content)
        div_list = html.xpath('.//div[@id="root"]/div/div/div/div/div/div[@class="item-root"]')
        # print(div_list)
        for div in div_list:
            item = {}
            """
            圖書名稱
            評分
            評價數
            詳情頁鏈接
            作者
            出版社
            價格
            出版日期
            """
            ## 圖書名稱
            name = self.get_text(div.xpath('.//div[@class="title"]/a/text()'))
            ## 評分
            score = self.get_text(div.xpath('.//span[@class="rating_nums"]/text()'))
            ## 評價數
            comment = self.get_text(div.xpath('.//span[@class="pl"]/text()'))
            ## 詳情頁鏈接
            detail_url = self.get_text(div.xpath('.//div[@class="title"]/a/@href'))

            ## 價格
            all_info = self.get_text(div.xpath('.//div[@class="meta abstract"]/text()'))
            if all_info:
                info_list = all_info
            else:
                info_list = '"未知"/"未知"/ "未知"/ "未知"'
            info_list = info_list.split('/')
            price = info_list.pop()
            ## 出版日期
            data = info_list.pop()
            ## 出版社
            publish = info_list.pop()
            ## 作者
            author = '/'.join(info_list)

            if all([name, detail_url, author, publish, data, price]):
                item["圖書名稱"] = name
                item["評分"] = score
                item["評價數"] = comment
                item["詳情頁鏈接"] = detail_url
                item["價格"] = price
                item["出版日期"] = data
                item["出版社"] = publish
                item["作者"] = author
            print(item)
            self.info_list.append(item)

if __name__ == '__main__':
    base_url = 'http://book.douban.com/subject_search?'
    db = Douban(base_url,"python")
    with open('douban.json','w',encoding='utf-8') as fp:
        json.dump(db.info_list,fp)

with open('douban.json','r') as fp:
    json.load(fp)

案例:騰訊招聘

import requests,time,re
from lxml import etree
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

from urllib import parse

class Tencent(object):
    def __init__(self,url):
        self.url = url
        self.driver = webdriver.PhantomJS()
        ## 顯性等待  有三個參數,第一個爲driver對象;第二個爲最大等待時間,單位秒;第三個默認0.5秒刷新一次
        self.wait = WebDriverWait(self.driver,10)
        self.parse()

    def get_text(self,text):
        if text:
            return text[0]
        return ''

    def get_content_by_selenium(self,url,xpath):
        self.driver.get(url)
        #等待
        # time.sleep(3)
        #等到什麼完成,until方法裏面就是一些條件。
        #locator對象是一個元組
        ## 顯性等待等待到什麼時候
        webelement = self.wait.until(EC.presence_of_element_located((By.XPATH,xpath)))

        return self.driver.page_source

    def parse(self):
        """
        title
       工作簡介
       工作地點
       發佈時間
       崗位類別
       詳情頁鏈接
        """
        html_str = self.get_content_by_selenium(self.url,'//div[@class="correlation-degree"]')
        html = etree.HTML(html_str)
        div_list = html.xpath('.//div[@class="recruit-list"]')
        # print(div_list)
        for div in div_list:
            item={}
            ## 工作名稱
            title = self.get_text(div.xpath('.//a[@class="recruit-list-link"]/h4/text()'))
            ## 工作地點
            location = self.get_text(div.xpath('.//p[@class="recruit-tips"]/span[2]/text()'))
            ## 工作簡介
            detail = self.get_text(div.xpath('.//p[@class="recruit-text"]/text()')).replace('\n','')
            ## 發佈時間
            date= self.get_text(div.xpath('.//p[@class="recruit-tips"]/span[last()]/text()'))
            ## 崗位類別
            job_type = self.get_text(div.xpath('.//p[@class="recruit-tips"]/span[3]/text()'))
            item["工作名稱"] = title
            item["工作地點"] = location
            item["工作簡介"] = detail
            item["發佈時間"] = date
            item["崗位類別"] = job_type
            print(item)

if __name__ == '__main__':
    base_url = 'https://careers.tencent.com/search.html?index=%s'
    for i in range(1,100):
        Tencent(base_url %i)



發佈了107 篇原創文章 · 獲贊 43 · 訪問量 7063
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章