文章目錄
一、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)