前面爬蟲大多使用的是urllib 庫, 另外還有requests 庫。urllib 可以解決好多問題,包括代理、自定義請求體、cookie 設(shè)置等。 這些庫都是模擬瀏覽器進行訪問,畢竟是模擬,有些網(wǎng)站針對反爬會造成爬取的數(shù)據(jù)不準確。
這時候就需要引入selenium, selenuim 是真實的驅(qū)動瀏覽器,然后模擬人工操作去進行一系列的操作。
? 舉個簡單的例子: 京東官網(wǎng) https://www.jd.com/ 首頁,如果通過網(wǎng)頁訪問我們能拿到秒殺模塊; 如果是通過urllib 訪問拿到首頁源碼,發(fā)現(xiàn)沒有該模塊。該模塊所在區(qū)域的xpath 選擇器是: //*[@id='J_seckill']
? selenium 是驅(qū)動瀏覽器,然后去進行一系列的操作,所以我們需要下載對應(yīng)的驅(qū)動。
? chrome 驅(qū)動: http://chromedriver.storage.googleapis.com/index.html 根據(jù)自己的chrome 版本下載對應(yīng)的驅(qū)動, 大版本一致即可,windows 安裝包32 位也可以的。
? 驅(qū)動下載完成后將解壓后的exe驅(qū)動程序拷貝到運行程序同級目錄,或者就放到python 目錄然后加入到path 換變量中也可以。需要程序能找到該exe。
File→Settings→Project:項目名稱→python Interpreter->添加selenium
pycharm 安裝完成后可以到項目的venv\lib 目錄查看現(xiàn)有的模塊
如果是想python 跑對應(yīng)腳本,需要本地安裝selenium
pip install selenium
測試可以在python 窗口輸入:
from selenium import webdriver
from selenium import webdriver
browser = webdriver.Chrome("chromedriver.exe")
browser.get("https://www.jd.com/")
# 獲取網(wǎng)頁源碼
content = browser.page_source
print(content)
# 打印url
print(browser.current_url)
# 保存為圖片(注意這里只能保存為png,不支持jpg)
browser.save_screenshot("jd.png")
# 打印title
print(browser.title)
# 窗口最大化
browser.maximize_window()
# 關(guān)閉
browser.close()
? 會自動打開瀏覽器,然后訪問京東的首頁。然后打印網(wǎng)頁源碼(從源碼可以搜索到id 為 J_seckill 的div)。最后將網(wǎng)頁保存為圖片后關(guān)閉瀏覽器。
獲取元素主要有下面六個API:當(dāng)然返回的元素還可以繼續(xù)調(diào)用find_element 元素向下查找。
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome("chromedriver.exe")
browser.get("https://www.baidu.com/")
# 獲取網(wǎng)頁源碼
# content = browser.page_source
# print(content)
'''
元素定位(改版后主要有兩個方法)。
兩個方法參數(shù)一樣
第一個指定模式: 參考 selenium.webdriver.common.by.By;
class By:
"""
Set of supported locator strategies.
"""
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
第二個指定屬性的值
find_element(by=By.ID, value=None) 查找單個元素,WebElement。 內(nèi)部調(diào)用查找集合方法,然后返回第一個元素
find_elements(by=By.ID, value=None) 查找集合, WebElement 集合
'''
# 根據(jù)ID查找 (百度首頁的百度一下按鈕)
# button = browser.find_element(by=By.ID, value="su")
# print(button)
# 根據(jù)name屬性查找 (查找百度首頁的輸入框)
# input = browser.find_element(by=By.NAME, value="wd")
# print(input)
# 根據(jù)xpath 語法查找 (查找百度首頁的輸入框)
# input = browser.find_element(by=By.XPATH, value="//input[@name='wd']")
# print(input)
# 根據(jù)標簽的名字查找
# inputs = browser.find_elements(by=By.TAG_NAME, value="input")
# print(len(inputs))
# 根據(jù)link 內(nèi)容查找 也就是根據(jù)<a>測試</a> 內(nèi)部的text 屬性查找
# a = browser.find_element(by=By.LINK_TEXT, value="新聞")
# print(a.text)
# css 選擇器查找(找百度首頁輸入框)
a = browser.find_element(by=By.CSS_SELECTOR, value="#kw")
print(a.get_attribute("name"))
# 關(guān)閉
browser.close()
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome("chromedriver.exe")
browser.get("https://www.baidu.com/")
# 根據(jù)link 內(nèi)容查找 也就是根據(jù)<a>測試</a> 內(nèi)部的text 屬性查找
a = browser.find_element(by=By.LINK_TEXT, value="新聞")
# 獲取屬性
print(a.get_attribute("href"))
# 獲取text
print(a.text)
# 獲取tag
print(a.tag_name)
# 關(guān)閉
browser.close()
點擊: click()
輸入: send_keys()
清空輸入: clear()
后退:browser.back()
快進:browser.forward()
模擬JS滾動: js = 'document.body.scrollTop=100000'
js = 'document.documentElement.scrollTop=100000'
browser.execute_script(js) # 執(zhí)行JS代碼
獲取網(wǎng)頁源碼: browser.page_source
一個簡單的例子,過程如下:
1.打開百度首頁,睡眠2s
2.輸入java,睡眠2s
3.點擊百度一下按鈕,睡眠5s
4.滾動到底部,睡眠5s
5.翻到第二頁,睡眠5s
6.點擊后退回退到第一頁,睡眠5s
7.點擊前進再回去第二頁, 睡眠5s
8.結(jié)束
代碼:
import time
from selenium import webdriver
# 1.打開百度首頁,睡眠2s
from selenium.webdriver.common.by import By
browser = webdriver.Chrome("chromedriver.exe")
browser.get("https://www.baidu.com/")
time.sleep(2)
# 2.輸入java,睡眠2s
input = browser.find_element(value="kw")
input.send_keys("java")
time.sleep(2)
# 3.點擊百度一下按鈕,睡眠5s
button = browser.find_element(value="su")
button.click()
time.sleep(5)
# 4.滾動到底部,睡眠5s
js = 'document.body.scrollTop=100000'
browser.execute_script(js)
time.sleep(5)
# 5.翻到第二頁,睡眠5s
nextBtn = browser.find_element(by=By.XPATH, value="//a[@class='n']")
nextBtn.click()
time.sleep(5)
# 6. 點擊后退回退到第一頁,睡眠5s
browser.back()
time.sleep(5)
# 7. 點擊前進再回去第二頁, 睡眠5s
browser.forward()
time.sleep(5)
# 8. 關(guān)閉
browser.close()
打開瀏覽器再啟動會浪費時間,對爬蟲的性能也是個影響,還有一種就是不打開瀏覽器。
如下參數(shù)是針對chrome 的全局參數(shù),不能自定義參數(shù)。
from selenium import webdriver
# 還有一些其他的參數(shù)
'''
# 添加UA
options.add_argument('user-agent="MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"')
# 設(shè)置代理
options.add_argument("--proxy-server=http://110.52.235.176:9999") # 設(shè)置代理,請求頭等,以列表的形式傳入多個參數(shù)
# 設(shè)置編碼格式
options.add_argument('lang=zh_CN.UTF-8') # 設(shè)置編碼格式
# 啟動時最大化窗口
options.add_argument('--start-maximized')
# 指定瀏覽器分辨率
options.add_argument('window-size=1920x3000')
# 谷歌文檔提到需要加上這個屬性來規(guī)避bug
options.add_argument('--disable-gpu')
# 隱藏滾動條, 應(yīng)對一些特殊頁面
options.add_argument('--hide-scrollbars')
# 不加載圖片, 提升速度
options.add_argument('blink-settings=imagesEnabled=false')
# 瀏覽器不提供可視化頁面. linux下如果系統(tǒng)不支持可視化不加這條會啟動失敗
options.add_argument('--headless')
# 以最高權(quán)限運行
options.add_argument('--no-sandbox')
# 手動指定使用的瀏覽器位置
options.binary_location = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
#添加crx插件
option.add_extension('d:\crx\AdBlock_v2.17.crx')
# 禁用JavaScript
option.add_argument("--disable-javascript")
# 設(shè)置開發(fā)者模式啟動,該模式下webdriver屬性為正常值
options.add_experimental_option('excludeSwitches', ['enable-automation'])
# 禁用瀏覽器彈窗
prefs = {
'profile.default_content_setting_values' : {
'notifications' : 2
}
}
options.add_experimental_option('prefs',prefs)
'''
option = webdriver.ChromeOptions()
# 瀏覽器不提供可視化頁面. linux下如果系統(tǒng)不支持可視化不加這條會啟動失敗
option.add_argument("--headless")
# 谷歌文檔提到需要加上這個屬性來規(guī)避bug
option.add_argument('--disable-gpu')
browser = webdriver.Chrome(executable_path="chromedriver.exe", options=option)
browser.get("https://www.jd.com/")
# 獲取網(wǎng)頁源碼
print(browser.title)
# 關(guān)閉
browser.close()
from selenium import webdriver
from selenium.webdriver.common.by import By
option = webdriver.ChromeOptions()
# 瀏覽器不提供可視化頁面. linux下如果系統(tǒng)不支持可視化不加這條會啟動失敗
option.add_argument("--headless")
# 谷歌文檔提到需要加上這個屬性來規(guī)避bug
option.add_argument('--disable-gpu')
# 添加代理
option.add_argument("--proxy-server=http://221.11.233.111:4315") # 設(shè)置代理,請求頭等,以列表的形式傳入多個參數(shù)
browser = webdriver.Chrome(executable_path="chromedriver.exe", options=option)
browser.get("http://www.ipdizhichaxun.com/")
# 獲取網(wǎng)頁源碼
result = browser.find_element(by=By.XPATH, value='//*[@class="result"]')
print(result.text)
# 關(guān)閉
browser.close()
結(jié)果:
IP地址查詢結(jié)果:221.11.233.111,IP地址位置:寧夏石嘴山市(聯(lián)通)
import time
from selenium import webdriver
browser = webdriver.Chrome(executable_path="chromedriver.exe")
# 刪除原來的cookie
browser.delete_all_cookies()
# 注意需要訪問一次才能添加cookie。 selenium的默認域名為data,cookie中帶域名,在設(shè)置cookie時發(fā)現(xiàn)當(dāng)前域名不包含在cookie中,所以設(shè)置失敗,一直都是data的這個頁面
browser.get("http://127.0.0.1:8088/inner/t4")
# 攜帶cookie打開
browser.add_cookie({'name': 'ABC', 'value': 'DEF'})
browser.get("http://127.0.0.1:8088/inner/t4")
browser.refresh()
browser.close()
time.sleep(10)
? 如果不設(shè)置等待時間,find_element會立即查找元素,找不到就會立即報錯。一般會設(shè)置下時間,讓JS渲染完成再找元素。
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome("chromedriver.exe")
# 設(shè)置等待時間,最長等待20 s。 不設(shè)置等待事件, find_element 找不到元素會拋出異常,設(shè)置完成之后不會報異常,會阻塞直到拿取到對應(yīng)的元素或者達到指定時間
browser.implicitly_wait(20)
browser.get("http://baidu.com")
print(browser.find_element(by=By.XPATH, value='//div[@class="content"]//img'))
# 關(guān)閉
browser.close()
繼續(xù)改進,找不到元素返回None 或者其他處理:
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome("chromedriver.exe")
# 設(shè)置等待時間,最長等待20 s。 不設(shè)置等待事件, find_element 找不到元素會拋出異常,設(shè)置完成之后不會報異常,會阻塞直到拿取到對應(yīng)的元素或者達到指定時間
browser.implicitly_wait(20)
browser.get("http://baidu.com")
try:
print(browser.find_element(by=By.XPATH, value='//div[@class="content"]//img'))
except Exception as e:
# ignore
print("沒有元素")
# 關(guān)閉
browser.close()
可以用ActionChains, 最后調(diào)用其perform() 方法就是提交事件
# 找到第一個節(jié)點然后擴展
node1 = browser.find_element(by=By.XPATH,value=' //*[name()="svg"]//*[name()="g"]/*[@class="node"][1]')
# 調(diào)用ActionChains方法,生成一個動作
# 創(chuàng)建一個ActionChains, 然后可以進行一系列事件、包括右鍵、雙擊、單擊、拖拽、鍵盤按下、鍵盤抬起等事件
action = ActionChains(browser)
# 單擊
action.click(node1)
# 雙擊
# action.double_click(node1)
# 右擊
action.context_click(node1)
action.perform()
補充:
(1). 測試過程中發(fā)現(xiàn)browser 關(guān)閉之后,驅(qū)動程序不會關(guān)系,需要自己cmd 關(guān)閉下:
taskkill -im chromedriver.exe -f
(2). selenium 可以獲取元素大小location、size、rect
這里需要注意獲取到的元素的坐標是相對于瀏覽器內(nèi)容區(qū)域左上角為原點,也就是不包含頭部瀏覽器菜單欄高度。
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome("chromedriver.exe")
browser.maximize_window()
browser.get("https://www.baidu.com/")
# css 選擇器查找(找百度首頁輸入框)
a = browser.find_element(by=By.CSS_SELECTOR, value="#kw")
print(a.get_attribute("name"))
print(a.location)
print(a.size)
# rect = location + size
print(a.rect)
# 關(guān)閉
browser.close()
結(jié)果:
wd
{'x': 633, 'y': 222}
{'height': 44, 'width': 550}
{'height': 44, 'width': 550, 'x': 633, 'y': 222}
(3) 上面提到獲取的元素的location是相對于瀏覽器可視區(qū)域的左上角為原點,也就是不包括菜單欄的高度。所以當(dāng)和pyautogui 結(jié)合,自動進行鼠標操作的時候需要加上菜單欄高度:
@staticmethod
def middle_location(element: WebElement):
ele_location = element.location
ele_size = element.size
middle_x = ele_location.get('x') + ele_size.get('width') / 2
middle_y = ele_location.get('y') + ele_size.get('height') / 2 + ChromeBrowserContext.browser_bar_height()
return middle_x, middle_y
@staticmethod
def browser_bar_height():
'''
獲取當(dāng)前broswer菜單欄高度
:return:
'''
# 執(zhí)行js 并且拿到結(jié)果
innerHeight = ChromeBrowserContext.__browser.execute_script("return window.innerHeight")
outerHeight = ChromeBrowserContext.__browser.execute_script("return window.outerHeight")
return outerHeight - innerHeight
(4) 結(jié)合pyautogui 實現(xiàn)拖拽方法
@staticmethod
def dragToByXpath(xpath1: str, xpath2: str, time: int):
'''
拖拽元素
:param xpath1: 元素1
:param xpath2: 元素2
:param time: 時間
:return:
'''
browser = ChromeBrowserContext.getBrowser()
xpath1Element = browser.find_element(by=By.XPATH, value=xpath1)
x, y = ChromeBrowserContext.middle_location(xpath1Element)
pyautogui.moveTo(x, y)
xpath2Element = browser.find_element(by=By.XPATH, value=xpath2)
x, y = ChromeBrowserContext.middle_location(xpath2Element)
pyautogui.dragTo(x, y, time)
@staticmethod
def dragToByElement(element1: WebElement, element2: WebElement, time: int):
'''
拖拽元素
:param element1: 元素1
:param element2: 元素2
:param time: 時間
:return:
'''
x, y = ChromeBrowserContext.middle_location(element1)
pyautogui.moveTo(x, y)
x, y = ChromeBrowserContext.middle_location(element2)
pyautogui.dragTo(x, y, time)
在自己的測試過程中發(fā)現(xiàn),selenium不支持動態(tài)修改header , 而且好像不能自定義header 進行請求。可以通過插件或者其他機制實現(xiàn)。
官網(wǎng): https://github.com/wkeeling/selenium-wire 強烈建議直接使用這個庫
? selenium-wire 對selenium 做了擴展,讓程序有能力拿到requests 對象,然后獲取請求和響應(yīng)信息,并且可以修改請求頭(包括自定義的頭)、修改請求參數(shù)(包括param和請求體中的JSON數(shù)據(jù))、獲取修改響應(yīng)頭等信息。
下面演示增加自己的header:(請求攔截器與響應(yīng)攔截器用法)
from seleniumwire import webdriver
# 攔截request
def interceptor_request(request):
del request.headers['mykey'] # Remember to delete the header first
request.headers['mykey'] = 'mykey-value' # Spoof the referer
# 攔截response
def interceptor_response(request, response):
if request.url == 'http://localhost:8088/inner/t4':
response.headers['New-Header'] = 'Some Value'
browser = webdriver.Chrome("chromedriver.exe")
browser.request_interceptor = interceptor_request
browser.response_interceptor = interceptor_response
browser.get("http://localhost:8088/inner/t4")
for request in browser.requests:
if request.response:
print(
request.url,
request.response.status_code,
request.response.headers
)
需要注意,進程結(jié)束之后browser 也是close 狀態(tài)的,無法進行后續(xù)頁面刷新或請求數(shù)據(jù)。
AJAX(Asynchronouse JavaScript And XML:異步JavaScript和XML)通過在后臺與服務(wù)器進行少量數(shù)據(jù)交換,Ajax 可以使網(wǎng)頁實現(xiàn)異步更新,這意味著可以在不重新加載整個網(wǎng)頁的情況下,對網(wǎng)頁的某部分進行局部更新。傳統(tǒng)的網(wǎng)頁(不使用Ajax)如果需要更新內(nèi)容,必須重載整個網(wǎng)頁頁面。
因為傳統(tǒng)的網(wǎng)頁在傳輸數(shù)據(jù)格式方面,使用的是XML語法,因此叫做AJAX,其實現(xiàn)在數(shù)據(jù)交互基本上都是使用JSON。使用AJAX加載的數(shù)據(jù),即使使用了JS將數(shù)據(jù)渲染到了瀏覽器中,在右鍵->查看網(wǎng)頁源代碼還是不能看到通過ajax加載的數(shù)據(jù),只能看到使用這個url加載的html代碼。
法1:直接分析ajax調(diào)用的接口。然后通過代碼請求這個接口。
法2:使用Selenium+chromedriver模擬瀏覽器行為獲取數(shù)據(jù)。
方式 | 優(yōu)點 | 缺點 |
分析接口 | 直接可以請求到數(shù)據(jù)。不需要做一些解析工作。代碼量少,性能高。 | 分析接口比較復(fù)雜,特別是一些通過js混淆的接口,要有一定的js功底。容易被發(fā)現(xiàn)是爬蟲。 |
selenium | 直接模擬瀏覽器的行為。瀏覽器能請求到的,使用selenium也能請求到。爬蟲更穩(wěn)定。 | 代碼量多。性能低。 |
Selenium相當(dāng)于是一個機器人。可以模擬人類在瀏覽器上的一些行為,自動處理瀏覽器上的一些行為,比如點擊,填充數(shù)據(jù),刪除cookie等。chromedriver是一個驅(qū)動Chrome瀏覽器的驅(qū)動程序,使用他才可以驅(qū)動瀏覽器。當(dāng)然針對不同的瀏覽器有不同的driver。以下列出了不同瀏覽器及其對應(yīng)的driver:
現(xiàn)在以一個簡單的獲取百度首頁的例子來講下Selenium和chromedriver如何快速入門:
from selenium import webdriver
# chromedriver的絕對路徑
driver_path = r'D:\ProgramApp\chromedriver\chromedriver.exe'
# 初始化一個driver,并且指定chromedriver的路徑
driver = webdriver.Chrome(executable_path=driver_path)
# 請求網(wǎng)頁
driver.get("https://www.baidu.com/")
# 通過page_source獲取網(wǎng)頁源代碼
print(driver.page_source)
參考:Selenium的使用
直接直接分析ajax調(diào)用的接口爬取
import requests
from lxml import etree
import time
import re
headers = {
"Accept":"application/json, text/javascript, */*; q=0.01",
"Accept-Encoding":"gzip, deflate, br",
"Accept-Language":"zh-CN,zh;q=0.9",
"Connection":"keep-alive",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36",
"Referer":"https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=",
"Origin":"https://www.lagou.com",
"Host":"www.lagou.com",
"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
"Cookie":"_ga=GA1.2.1602115737.1553064534; user_trace_token=20190320144853-39b1375a-4adc-11e9-a253-525400f775ce; LGUID=20190320144853-39b13f88-4adc-11e9-a253-525400f775ce; WEBTJ-ID=20190408120043-169fb1afd63488-06179b118ca307-7a1437-2073600-169fb1afd648ed; _gid=GA1.2.1826141825.1554696044; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22169fb1bb2c41ea-04951e55adc96a-7a1437-2073600-169fb1bb2c58d0%22%2C%22%24device_id%22%3A%22169fb1bb2c41ea-04951e55adc96a-7a1437-2073600-169fb1bb2c58d0%22%7D; sajssdk_2015_cross_new_user=1; _putrc=4C5D2603888320CA; JSESSIONID=ABAAABAAADEAAFIB00F5DDE71D51610901CB9E0031812BA; login=true; unick=%E4%BC%8D%E6%99%93%E4%B8%BD; showExpriedIndex=1; showExpriedCompanyHome=1; showExpriedMyPublish=1; hasDeliver=49; gate_login_token=7b04a40da89145a1fbc90a3d719616d28c8b0a303344ac37; index_location_city=%E6%88%90%E9%83%BD; X_MIDDLE_TOKEN=1221e6b5040722dc86f5ceb557e11965; _gat=1; LGSID=20190408151935-a9976fbf-59ce-11e9-8cc8-5254005c3644; PRE_UTM=m_cf_cpc_baidu_pc; PRE_HOST=www.baidu.com; PRE_SITE=https%3A%2F%2Fwww.baidu.com%2Fbaidu.php%3Fsc.Ks000001qLT2daZnZWIez3ktR_jhHue3tONZubxU9mivhxeuj-Fxrjg6NnVcKTp-GYJ_YRvrc9_yOJ4uV-IEpfnPazPz7ctjve1qlDokCDfHYo9PV0uDfTmN1OunNUcCRU-sJuR8RZz60PAXzfKybAdvuCxUedbt8aWtTjAdCCuO298TwT8zN1-T5EG3kgkOweg0DHGIbvP55IZbr6.DY_NR2Ar5Od663rj6tJQrGvKD7ZZKNfYYmcgpIQC8xxKfYt_U_DY2yP5Qjo4mTT5QX1BsT8rZoG4XL6mEukmryZZjzsLTJplePXO-8zNqrw5Q9tSMj_qTr1x9tqvZul3xg1sSxW9qx-9LdoDkY4QPSl81_4pqO24rM-8dQjPakb3dS5iC0.U1Yk0ZDqs2v4VnL30ZKGm1Yk0Zfqs2v4VnL30A-V5HcsP0KM5gK1n6KdpHdBmy-bIykV0ZKGujYzr0KWpyfqnWcv0AdY5HDsnHIxnH0krNtknjc1g1nsnHNxn1msnfKopHYs0ZFY5HDLn6K-pyfq0AFG5HcsP0KVm1Y3nHDYP1fsrjuxnH0snNtkg1Dsn-ts0Z7spyfqn0Kkmv-b5H00ThIYmyTqn0K9mWYsg100ugFM5H00TZ0qPWm1PHm1rj640A4vTjYsQW0snj0snj0s0AdYTjYs0AwbUL0qn0KzpWYs0Aw-IWdsmsKhIjYs0ZKC5H00ULnqn0KBI1Ykn0K8IjYs0ZPl5fK9TdqGuAnqTZnVUhC0IZN15Hnkn1fknHT4P1DvPHR1PW61P100ThNkIjYkPHRYP10LrHTkPjTY0ZPGujd9rAwBmhuWrj0snjDzrj0Y0AP1UHYsPbm3wWTsrH0srjwarDcz0A7W5HD0TA3qn0KkUgfqn0KkUgnqn0KlIjYs0AdWgvuzUvYqn7tsg1Kxn7ts0Aw9UMNBuNqsUA78pyw15HKxn7tsg1nkrjm4nNts0ZK9I7qhUA7M5H00uAPGujYknjT1P1fkrjcY0ANYpyfqQHD0mgPsmvnqn0KdTA-8mvnqn0KkUymqn0KhmLNY5H00uMGC5H00uh7Y5H00XMK_Ignqn0K9uAu_myTqnfK_uhnqn0KEIjYs0AqzTZfqnanscznsc100mLFW5HRdPj0Y%26word%3D%25E6%258B%2589%25E5%258B%25BE%25E7%25BD%2591%26ck%3D1701.10.72.227.558.354.602.254%26shh%3Dwww.baidu.com%26sht%3D62095104_19_oem_dg%26us%3D1.0.1.0.1.301.0%26bc%3D110101; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2Flp%2Fhtml%2Fcommon.html%3Futm_source%3Dm_cf_cpc_baidu_pc%26m_kw%3Dbaidu_cpc_cd_e110f9_d2162e_%25E6%258B%2589%25E5%258B%25BE%25E7%25BD%2591; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1553064535,1554696044,1554707975; TG-TRACK-CODE=index_search; SEARCH_ID=16b25888bc6f489f981996ef505d6930; X_HTTP_TOKEN=3704e5535eab672a10080745514b2c7fac0430c282; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1554708001; LGRID=20190408152002-b9743b5b-59ce-11e9-9a84-525400f775ce",
"X-Anit-Forge-Code":"0" ,
"X-Anit-Forge-Token":'',
"X-Requested-With":'XMLHttpRequest'
}
def get_detail_page_url():
datas =[]
url = 'https://www.lagou.com/jobs/positionAjax.json'
form_data = {
"first":"faise",
"pn":1,
"kd":"python"
}
params = {
'city':'成都',
'needAddtionalResult':'false'
}
for pn in range(1,14):
form_data['pn'] = pn
response = requests.request(method='post',url=url,headers=headers,params = params,data = form_data)
result = response.json()
result_list = result['content']['positionResult']['result']
for position in result_list:
position_id = position['positionId']
detail_url = 'https://www.lagou.com/jobs/%s.html'%position_id
data = parse_detail_page(detail_url)
datas.append(data)
time.sleep(2)
return datas
def parse_detail_page(url):
resonse = requests.request(method='get',url=url,headers = headers)
text = resonse.text
html = etree.fromstring(text,parser=etree.HTMLParser())
position_name = html.xpath('//span[@class="name"]/text()')[0].strip()
detail_list = html.xpath('//dd[@class="job_request"]//span')
salary = detail_list[0].xpath('text()')[0].strip()
city = detail_list[1].xpath('text()')[0].strip()
city = re.sub(r'[\s/]','',city)
work_years = detail_list[2].xpath('text()')[0].strip()
work_years = re.sub(r'[\s/]','',work_years)
education = detail_list[3].xpath('text()')[0].strip()
education = re.sub(r'[\s/]','',education)
job_details = ''.join(html.xpath('//div[@class="job-detail"]//p//text()'))
data = {
"position_name":position_name,
"salay":salary,
"city":city,
"work_years":work_years,
"education":education,
"job_details":job_details
}
return data
def main():
datas = get_detail_page_url()
print(datas)
if __name__ == '__main__':
main()
selenium結(jié)合lxml爬取
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from lxml import etree
import re
import time
class Lagouspider(object):
driver_path = r'E:\study\chromedriver\chromedriver.exe'
def __init__(self):
self.driver = webdriver.Chrome(executable_path=Lagouspider.driver_path)
self.url = 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput='
self.positions = []
def run(self):
while True:
self.driver.get(self.url)
source = self.driver.page_source
WebDriverWait(driver=self.driver,timeout=10).until(EC.presence_of_element_located((By.XPATH,'//div[@class="pager_container"]/span[last()]')))
self.parse_list_page(source)
next_btn = self.driver.find_element_by_xpath('//div[@class="pager_container"]/span[last()]')
if "pager_next_disabled" in next_btn.get_attribute('class'):
break
else:
next_btn.click()
time.sleep(1)
def parse_list_page(self,source):
html = etree.HTML(source)
links = html.xpath('//a[@class="position_link"]/@href')
for link in links:
self.request_detail_page(link)
time.sleep(1)
def request_detail_page(self,url):
self.driver.execute_script("window.open('%s')"%url)
self.driver.switch_to.window(self.driver.window_handles[1])
WebDriverWait(self.driver,timeout=10).until(EC.presence_of_element_located((By.XPATH,'//span[@class="name"]')))
source = self.driver.page_source
self.parse_detail_page(source)
#關(guān)閉當(dāng)前詳情頁
self.driver.close()
#切換回職位列表頁
self.driver.switch_to.window(self.driver.window_handles[0])
def parse_detail_page(self,source):
html = etree.HTML(source)
position_name = html.xpath('//span[@class="name"]/text()')[0].strip()
detail_list = html.xpath('//dd[@class="job_request"]//span')
salary = detail_list[0].xpath('text()')[0].strip()
city = detail_list[1].xpath('text()')[0].strip()
city = re.sub(r'[\s/]', '', city)
work_years = detail_list[2].xpath('text()')[0].strip()
work_years = re.sub(r'[\s/]', '', work_years)
education = detail_list[3].xpath('text()')[0].strip()
education = re.sub(r'[\s/]', '', education)
desc = ''.join(html.xpath('//dd[@class="job_bt"]//text()')).strip()
data = {
"name": position_name,
"salay": salary,
"city": city,
"work_years": work_years,
"education": education,
"desc": desc
}
print(data)
print('+'*40)
self.positions.append(data)
if __name__ == '__main__':
spider = Lagouspider()
spider.run()
希望本文對你有所幫助~~如果對軟件測試、接口測試、自動化測試、面試經(jīng)驗交流感興趣可以私聊我或關(guān)注公眾號“特斯汀軟件測試”。免費領(lǐng)取最新軟件測試大廠面試資料和Python自動化、接口、框架搭建學(xué)習(xí)資料!技術(shù)大牛解惑答疑,同行一起交流。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。