@概述
通常各大網(wǎng)站的后臺都會有一定的反爬機制,既為了數(shù)據(jù)安全孤个,也為了減小服務器壓力
通常反爬的手段的方向陋率,都是識別非瀏覽器客戶端,而selenium所做的事情逮刨,恰恰是驅(qū)動真正的瀏覽器去執(zhí)行請求和操作呕缭,只不過信號不是來源于鼠標,而是來源于selenium的API(selenium本是一個自動化的測試工具)
自然人用戶能做的一切,selenium幾乎都驅(qū)動瀏覽器取做恢总,無論是否有界面迎罗,包括輸入、點擊片仿、滑動纹安,等等
然而到底是鼠標操作的瀏覽器發(fā)起的請求還是API,對于服務端來說滋戳,是沒有任何差別的
@一些掌故
早些的時候流行的組合并不是selenium+chrome瀏覽器驅(qū)動钻蔑,而是selenium+phantomjs
phantomjs是一款沒有界面的瀏覽器,業(yè)界稱作無頭瀏覽器(headless)奸鸯,由于沒有界面和渲染咪笑,其運行速度要大大優(yōu)于有界面的瀏覽器,這恰恰是爬蟲喜歡的娄涩,因此紅極一時后來chrome和火狐推出了無頭模式窗怒,且運行速度很流暢,phantomjs已然壽終正寢蓄拣,因此我們表過不提
@開發(fā)環(huán)境的搭建(本文在windows下)
- 安裝selenium:
pip install selenium
- 接著我們還要下載瀏覽器驅(qū)動
@配置環(huán)境
@導包
# 導入selenium的瀏覽器驅(qū)動接口
from selenium import webdriver
# 要想調(diào)用鍵盤按鍵操作需要引入keys包
from selenium.webdriver.common.keys import Keys
# 導入chrome選項
from selenium.webdriver.chrome.options import Options
@第一個程序:抓取頁面內(nèi)容扬虚,生成頁面快照
# 創(chuàng)建chrome瀏覽器驅(qū)動,無頭模式(超爽)
options = Options()
ptions.add_argument('--headless')
driver = webdriver.Chrome(chrome_options=chrome_options)
# 加載百度頁面
driver.get("http://www.baidu.com/")
# time.sleep(3)
# 獲取頁面名為wrapper的id標簽的文本內(nèi)容
data = driver.find_element_by_id("wrapper").text
print(data)
# 打印頁面標題 "百度一下球恤,你就知道"
print(driver.title)
# 生成當前頁面快照并保存
driver.save_screenshot("baidu.png")
# 關閉瀏覽器
driver.quit()
@模擬用戶輸入和點擊搜索辜昵,跟真人操作一樣!
# get方法會一直等到頁面被完全加載咽斧,然后才會繼續(xù)程序堪置,通常測試會在這里選擇 time.sleep(2)
driver.get("http://www.baidu.com/")
# id="kw"是百度搜索輸入框,輸入字符串"程序猿"
driver.find_element_by_id("kw").send_keys(u"程序猿")
# id="su"是百度搜索按鈕张惹,click() 是模擬點擊
driver.find_element_by_id("su").click()
time.sleep(3)
# 獲取新的頁面快照
driver.save_screenshot("程序猿.png")
# 打印網(wǎng)頁渲染后的源代碼
print(driver.page_source)
# 獲取當前頁面Cookie
print(driver.get_cookies())
# ctrl+a 全選輸入框內(nèi)容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL, 'a')
# ctrl+x 剪切輸入框內(nèi)容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL, 'x')
# 輸入框重新輸入內(nèi)容
driver.find_element_by_id("kw").send_keys("美女")
# 模擬Enter回車鍵
driver.find_element_by_id("su").send_keys(Keys.RETURN)
time.sleep(3)
# 清除輸入框內(nèi)容
driver.find_element_by_id("kw").clear()
# 生成新的頁面快照
driver.save_screenshot("美女.png")
# 獲取當前url
print(driver.current_url)
# 關閉瀏覽器
driver.quit()
@模擬用戶登錄
# 加載微博登錄頁
driver.get("http://passport.weibo.cn/signin/login?entry=mweibo&r=http%3A%2F%2Fweibo.cn%2F&backTitle=%CE%A2%B2%A9&vt=")
time.sleep(3)
# 找到輸入框舀锨,鍵入用戶名和密碼
driver.find_element_by_id('loginName').send_keys("worio.hainan@163.com")
driver.find_element_by_id('loginPassword').send_keys("Qq94313805")
# 點擊登錄按鈕
driver.find_element_by_id('loginAction').click()
time.sleep(3)
# 快照顯示已經(jīng)成功登錄
print(driver.save_screenshot('jietu.png'))
driver.quit()
@使用cookies登錄
# 加載知乎主頁,查看快照知此時處于未登錄狀態(tài)
driver.get("https://www.zhihu.com")
time.sleep(1)
print(driver.save_screenshot("zhihu_nocookies.png"))
# 操作瀏覽器登錄知乎并抓包cookies
zhihu_cookies = {
# 'aliyungf_tc' : 'AQAAAAR4YFOeswAAnLFJcVRd4MKOTTXu',
'l_n_c': '1',
'q_c1': '8572377703ba49138d30d4b9beb30aed|1514626811000|1514626811000',
'r_cap_id': 'MTc5M2Y0ODUzMjc0NDMzNmFkNTAzZDBjZTQ4N2EyMTc=|1514626811|a97b2ab0453d6f77c6cdefe903fd649ee8531807',
'cap_id': 'YjQyZTEwOWM4ODlkNGE1MzkwZTk3NmI5ZGU0ZTY2YzM=|1514626811|d423a17b8d165c8d1b570d64bc98c185d5264b9a',
'l_cap_id': 'MGE0NjFjM2QxMzZiNGE1ZWFjNjhhZmVkZWQwYzBkZjY=|1514626811|a1eb9f2b9910285350ba979681ca804bd47f12ca',
'n_c': '1',
'd_c0': 'AKChpGzG6QyPThyDpmyPhXaV-B9_IYyFspc=|1514626811',
'_xsrf': 'ed7cbc18-03dd-47e9-9885-bbc1c634d10f',
'capsion_ticket': '2|1:0|10:1514626813|14:capsion_ticket|44:NWY5Y2M0ZGJiZjFlNDdmMzlkYWE0YmNjNjA4MTRhMzY=|6cf7562d6b36288e86afaea5339b31f1dab2921d869ee45fa06d155ea3504fe1',
'_zap': '3290e12b-64dc-4dae-a910-a32cc6e26590',
'z_c0': '2|1:0|10:1514626827|4:z_c0|92:Mi4xYm4wY0FRQUFBQUFBb0tHa2JNYnBEQ1lBQUFCZ0FsVk5DNjAwV3dCb2xMbEhxc1FTcEJPenpPLWlqSS1qNm5KVEFR|d89c27ab659ba979a977e612803c2c886ab802adadcf70bcb95dc1951bdfaea5',
'__utma': '51854390.2087017282.1514626889.1514626889.1514626889.1',
'__utmb': '51854390.0.10.1514626889',
'__utmc': '51854390',
'__utmz': '51854390.1514626889.1.1.utmcsr=zhihu.com|utmccn=(referral)|utmcmd=referral|utmcct=/',
'__utmv': "51854390.100--|2=registration_date=20150408=1'3=entry_date=20150408=1",
}
# 將用戶登錄產(chǎn)生的cookies全部添加到當前會話
for k, v in zhihu_cookies.items():
driver.add_cookie({'domain': '.zhihu.com', 'name': k, 'value': v})
# 再次訪問知乎主頁并拍照宛逗,此時已經(jīng)是登錄狀態(tài)了
driver.get("https://www.zhihu.com")
time.sleep(3)
print(driver.save_screenshot("zhihu_cookies.png"))
# 退出瀏覽器
driver.quit()
@模擬滾動條的滾動(這個用常規(guī)的爬蟲很難實現(xiàn))
# 加載知乎主頁
driver.get("https://www.zhihu.com")
time.sleep(1)
# 加載本地cookies實現(xiàn)登錄
for k, v in zhihu_cookies.items():
driver.add_cookie({'domain': '.zhihu.com', 'name': k, 'value': v})
# 以登錄狀態(tài)再次發(fā)起訪問
driver.get("https://www.zhihu.com")
time.sleep(3)
# 將頁面滾動到最后坎匿,執(zhí)行多次
for i in range(3):
js = "var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)
time.sleep(3)
# 截圖并退出,頁面?zhèn)冗厺L動條已經(jīng)下滑了許多像素
print(driver.save_screenshot("zhihu_scroll.png"))
driver.quit()
@一邊滾動一邊加載
- 唯品會首頁的女裝圖片雷激,是一邊滾動一邊進行ajax異步加載的
- 這個靠常規(guī)的抓包實現(xiàn)起來很麻煩
- 使用selenium我們只需模擬用戶多次下拉滾動條替蔬,一段時間之后再重新拿取渲染好的頁面源碼,就可以像爬取靜態(tài)頁面那樣去爬取圖片了
- 類似這種操作屎暇,其實質(zhì)就是開掛进栽,是幾乎無法防守的
# 唯品會女裝圖片鏈接無法直接獲得
# 請求唯品會頁面
driver.get("https://category.vip.com/search-3-0-1.html?q=3|30036||&rp=30074|30063&ff=women|0|2|2&adidx=1&f=ad&adp=65001&adid=326630")
time.sleep(3)
# 逐漸滾動瀏覽器窗口,令ajax逐漸加載
for i in range(1, 10):
js = "var q=document.body.scrollTop=" + str(500 * i) # PhantomJS
js = "var q=document.documentElement.scrollTop=" + str(500 * i) # 谷歌 和 火狐
driver.execute_script(js)
print('=====================================')
time.sleep(3)
# 拿到頁面源碼
html = etree.HTML(driver.page_source)
all_img_list = []
# 得到所有圖片
img_group_list = html.xpath("http://img[contains(@id,'J_pic')]")
# img_group_list = html.xpath("http://img[starts-with(@id,'J_pic')]")
# 正則表達式匹配
# img_group_list = html.xpath(r'//img[re:match(@id, "J_pic*")]',namespaces={"re": "http://exslt.org/regular-expressions"})
# 收集所有圖片鏈接到列表
for img_group in img_group_list:
img_of_group = img_group.xpath(".//@data-original | .//@data-img-back | .//@data-img-side")
print(img_of_group)
all_img_list.append('\n'.join(img_of_group) + '\n')
# 將收集到的數(shù)據(jù)寫入文件
with open('vip.txt', 'w', encoding='utf-8') as f:
f.write('\n'.join(all_img_list))
# 退出瀏覽器
driver.quit()