爬蟲1.5-ajax資料爬取
阿新 • • 發佈:2018-12-29
目錄
爬蟲-ajax資料爬取
1. ajax資料
ajax (非同步JavaScript 和 XML)(讀作阿賈克斯),ajax可以時網頁實現非同步更新,一般使用的json資料互動,即在不重新載入整個頁面也可以對網頁的部分進行更新,ajax技術載入的資料在網頁原始碼中是看不到的,只能看到url載入的html部分
獲取ajax資料的兩種方式
1 分析ajax呼叫的介面,發現url的引數,再通過程式碼請求這個介面,直接拿到json資料,有時json資料可能是加密的,或者傳送post請求獲取json資料並且表單中的資料是按照一定規則寫的,這時需要分析js程式碼,就很麻煩了。
2 Selenium+chromedriver 獲取動態資料,Selenium 相當於可以模擬輸入、刪除和點選操作以及cookie chromedriver是一個驅動chrome瀏覽器的驅動程式,使用它可以驅動瀏覽器。這種方式可以直接獲取網頁中全部的程式碼,包括ajax技術載入的資料。例如有的網站點選“更多”按鈕後可以載入的資料,將全部被獲取。雖然這種方式簡單粗暴,但每次請求頁面時都會開啟一個頁面,載入資料和渲染頁面,顯得過於笨重。
2. selenium+chromedriver知識準備
chromedriver是谷歌瀏覽器的驅動程式,使用selenium可以操作它
chromedriver.exe需要放在一個非中文目錄下
2.1 selenium+chromedriver簡單操作
form selenium import webdriver driver_path = r'D:\chromedriver\chromedriver.exe' # 指明路徑 driver = webdriver.Chrome(executable_path=driver_path) # 建立driver例項,將路徑傳入 driver.get("https://www.baidu.com") # get方式開啟百度,注意一定要加https:// 否則會報錯 driver.page_source # 獲取原始碼,然後可以扔給正則表示式或者xpath解析,這裡可以直接獲取ajax資料 driver.close() #關閉一個頁面 driver.quit() #關閉整個瀏覽器
2.2 常用表單元素
input type='text/password/email/number' 文字框
button input [type='submit'] 按鈕 例如登陸
checkbox input type='checkbox' 例如記住密碼選項
select 下拉選單
2.3 模擬點選
driver.get('https://www.douban.com/')
remenberBtn = driver.find_element_by_id('form_remember')
remenberBtn.click()
2.4 行為鏈
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains #匯入driver和行為鏈類
driver_path = r'D:\chromedriver\chromedriver.exe' #指定路徑
driver = webdriver.Chrome(executable_path=driver_path) #建立物件
driver.get('https://www.qq.com/') #開啟網頁
moveTag = driver.find_element_by_xpath("//div[@class='more-txt']") #定位騰訊網中“更多”按鈕
clickTag = driver.find_element_by_xpath("//ul[@class='sub-list cf']/li[1]")
#定位“獨家”按鈕
actions =ActionChains(driver) # 建立行為鏈物件
actions.move_to_element(moveTag) # 移動到定位點
actions.click(moveTag) # 點選 好像不點選也可以
actions.move_to_element(clickTag) # 移動到”獨家“按鈕
actions.click(clickTag) # 點選
actions.perform() # 必須呼叫的函式 否則不會執行之前定義好的行為
# drver.find_element_by_xpath("") 意味著可以使用xpath語法找到想要點選的按鈕或輸入框
# 類似的還有id class css
2.5 頁面等待
1 隱式等待
driver.implicitly_wait(x) # x是等待時間 x秒
2 顯示等待
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
driver_path = r'D:\chromedriver\chromedriver.exe'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://new.qq.com/ch/ori/')
try:
WebDriverWait(driver, 10).until(
# 這裡使用WebDriverWait類填入引數 10代表等待10s未出現則丟擲異常
EC.presence_of_element_located((By.CLASS_NAME, 's '))
#這裡就是等待條件 即當class屬性=s 被載入後條件達成
)
finally:
print("2222") # 這樣的話當沒有等待到期望的條件就可以做其他事情
2.6 視窗
開啟多個視窗
driver.get('https://new.qq.com/ch/ori/')
driver.execute_script("window.open('https://www.douban.com/')")
#使用JavaScript指令碼開啟新頁面
driver.get('https://new.qq.com/ch/ori/')
driver.execute_script("window.open('https://www.douban.com/')") # 開啟兩個頁面
print(driver.current_url) # 列印當前url
driver.switch_to.window(driver.window_handles[1]) # 切換視窗 視窗列表中第二個視窗的索引是1
print(driver.current_url) # 列印當前url
2.7 代理ip
driver_path = r'D:\chromedriver\chromedriver.exe'
options = webdriver.ChromeOptions() # 建立配置物件
options.add_argument("--proxy-server=http://221.6.32.206:41816") # 寫入配置
driver = webdriver.Chrome(executable_path=driver_path, options=options) # 寫入引數
driver.get('https://www.baidu.com/s?wd=ip')
3. selenium+chromedriver實戰拉勾網爬蟲程式碼
# 拉勾網的反爬太噁心了,於是用selenium+chromedriver來爬,結果還是被封了,我去
import re
import time
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
class LagouSpider(object):
def __init__(self):
driver_path = r'D:\chromedriver\chromedriver.exe' # 指定chromedriver 的路徑
self.driver = webdriver.Chrome(executable_path=driver_path)
self.base_url = 'https://www.lagou.com/jobs/list_python?px=default&city=%E6%88%90%E9%83%BD#filterBox' # 拉勾網搜尋python的頁面url
self.data = [] # 用來存放字典
def get_url_list(self):
while True:
self.driver.get(self.base_url) # 訪問拉勾網
# 獲取頁面全部文字資訊,這裡可以直接獲取ajax技術返回的資料,
# 如果用requests庫需要找到傳送json請求的資料包
text = self.driver.page_source
try:
# 等待職位資訊的url出現,timeout=3s
WebDriverWait(self.driver, 3).until(
EC.presence_of_element_located((By.CLASS_NAME, 'position_link'))
)
# 獲取url並呼叫get_info函式
url_list = re.findall(r'<a class="position_link" href="(.*?)" target=.*?>', text, re.S)
for i in url_list:
self.get_info(i)
finally:
# 判斷是否已到最後一頁
if len(re.findall(r'class="pager_next pager_next_disabled"', text, re.S)) != 0:
self.driver.quit()
break
# 找到下一頁的位置並點選
else:
nextPageTag = self.driver.find_element_by_xpath("//div[@class='pager_container']/span[last()]")
nextPageTag.click()
def get_info(self, url):
# 開啟新視窗,移動driver,不移動無法獲取page_source
self.driver.execute_script("window.open('{}')".format(url))
self.driver.switch_to.window(self.driver.window_handles[1])
try:
# 提取資訊,因為職位描述資訊的標籤實在是太亂了,還是用xpath舒服一點
html = etree.HTML(self.driver.page_source)
work_name = re.findall(r'<div class="job-name" title="(.*?)">', self.driver.page_source, re.S)[0]
salary = re.findall(r'<span class="salary">(.*?)</span>', self.driver.page_source, re.S)[0]
# 獲取職位描述資訊
temp = html.xpath("//dd[@class='job_bt']//div/p/text()")
describe = ''
for i in temp:
describe += i
describe = re.subn(r'\s*', '', describe)
temp = {
'job_name': work_name,
'describe': describe[0],
'salary': salary
}
print(temp)
# 放入列表中,方便寫入csv或者txt
self.data.append(temp)
except:
# 出錯的頁面打印出來
print(url)
time.sleep(5)
finally:
# 關閉頁面,移動driver到最開始的base_url
self.driver.close()
self.driver.switch_to.window(self.driver.window_handles[0])
time.sleep(1)
def run(self):
self.get_url_list()
if __name__ == '__main__':
spider = LagouSpider()
spider.run()