selenium 模擬登陸淘寶:
https://mp.weixin.qq.com/s?__biz=MzI0OTc0MzAwNA==&mid=2247487680&idx=1&sn=e40947f382116ff59761f250ee45dce3
學爬蟲,總能聽到「模擬登錄」這四個字,究竟什麼是「模擬登錄」?
通俗一點講,「模擬登錄」就是程序用賬號和密碼自動登錄一個網站。然後,拿到只有登錄後,才能下載的網站數據。比如,我們只有登錄淘寶賬號之後,才能看到購物車裏有哪些東西,這裏,就以「模擬登錄」淘寶爲例進行講解
1. Selenium
模擬登錄無非兩種方法:
- 請求包分析模擬登錄。這個需要抓包分析請求,解析各種參數,還可能涉及一些加密算法。
- 自動化測試工具模擬登錄。這個可以繞過一些繁瑣的分析過程,直接定位元素進行操作,但也會遇到一些反爬策略。
兩者,都有各自的操作技巧。這裏使用自動化測試工具 Selenium 模擬登錄。
Selenium 是一個自動化測試工具,支持各種主流瀏覽器,例如 Chrome、Safari、Firefox 等。
不知道什麼是自動化測試工具沒關係,我會通過實戰操作,慢慢講解。
不管怎樣,先安裝 Selenium 再說。
pip install selenium
使用 pip 直接安裝 selenium。
除了安裝 Python 的 Selenium 第三方庫,還需要根據瀏覽器配置相應的瀏覽器驅動。
安裝三大瀏覽器驅動 driver
1. chromedriver 下載地址:http://chromedriver.chromium.org
chromedriver 鏡像下載地址 :http://npm.taobao.org/mirrors/chromedriver
2. Firefox 的驅動 geckodriver 下載地址:https://github.com/mozilla/geckodriver/releases
3. IE 的驅動 IEdriver 下載地址:http://www.nuget.org/packages/Selenium.WebDriver.IEDriver
注意:下載解壓後,將chromedriver.exe , geckodriver.exe , Iedriver.exe 放到 Python 的安裝目錄,例如 D:\python 。 然後再將 Python 的安裝目錄添加到系統環境變量的 Path下面。
爬蟲 Selenium Chromium 與 Chromedriver對應版本( 注意是 chromium,不是 Chrome ):
淘寶鏡像地址在每個文件夾的 notes.txt 中存有 chromium 和 Chromedriver 的版本對應(一般3個chromium版本對應1個Chromedriver 版本)。
chromium | chromedriver |
v64-66 | v2.37 |
v63-65 | v2.36 |
v62-64 | v2.35 |
v61-63 | v2.34 |
v60-62 | v2.33 |
然後打開 Python IDE 分別輸入以下代碼來啓動不同的瀏覽器
# 啓動谷歌瀏覽器
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')
# 啓動火狐瀏覽器
from selenium import webdriver
browser = webdriver.Firefox()
browser.get('http://www.baidu.com/')
# 啓動IE瀏覽器
from selenium import webdriver
browser = webdriver.Ie()
browser.get('http://www.baidu.com/')
2. 小試牛刀
使用 Selenium 登錄百度看一下。
from selenium import webdriver
if __name__ == "__main__":
browser = webdriver.Chrome(r'D:\software\Python3\chromedriver.exe')
# browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
pass
結果如下圖所示:
程序會自動打開 Chrome 瀏覽器,並打開 www.baidu.com。
再來個複雜一些的例子。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
if __name__ == "__main__":
# driver = webdriver.Chrome("path\to\your\chromedriver.exe")
driver = webdriver.Chrome()
driver.get("https://www.python.org")
assert "Python" in driver.title
elem = driver.find_element_by_name("q")
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
print(driver.page_source)
運行結果:
寫好程序,瀏覽器自動操作,是不是很簡單,很酷炫?
這就是自動化測試工具,程序寫好,瀏覽器自動執行你的寫的操作。
find_element_by_* 是一種定位網頁元素的方法,有很多方式:
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
可以通過,標籤的 id 屬性、name 屬性、class_name 屬性查找元素,也可以通過 xpath 等。
這裏面,其實用到最多的就是 xpath,因爲好用。
不用動腦思考怎麼寫 xpath,就能操作,方便好用。舉個例子,比如我想找到 baidu.com 的搜索框的元素:
在搜索框位置,點擊右鍵,選擇 copy 下的 copy xpath,直接複製 xpath 。
粘貼出來你會看到如下內容://*[@id="kw"]
其實意思就是從根目錄開始找,找到 id 屬性爲 kw 的標籤。
定位到搜索框,就可以通過百度輸入 Jack Cui,搜索我的相關內容。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
if __name__ == "__main__":
# driver = webdriver.Chrome("path\to\your\chromedriver.exe")
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
elem = driver.find_element_by_xpath('//*[@id="kw"]')
elem.send_keys("Jack Cui")
elem.send_keys(Keys.RETURN)
運行結果:
可以看到,運行程序,搜索 Jack Cui,能搜到我的個人網站、CSDN 和知乎等。
Selenium 就是這麼簡單省事。
如果想學習更多,關於 Selenuim 其他的基本方法和 Xpath 的基礎知識,可以看下面文章。
文章地址:https://blog.csdn.net/c406495762/article/details/72331737
詳細的,關於 Selenium 的 API 文檔,可以看官方手冊。
官方手冊:https://selenium-python.readthedocs.io/index.html
好了,基礎知識準備完畢。
只要你會使用 copy xpath,基本的 Selenium 操作,就可以開始跟我一起「模擬登錄」淘寶。
3. 登陸淘寶,掏空錢包
1. 模擬登錄淘寶
用 Selenium 模擬登錄,就邊看邊寫,按照人的操作步驟寫代碼即可。
打開淘寶,上來第一步肯定是點擊登錄按鈕,不會寫 XPath,那就複製這個標籤的 XPath。
因此點擊登錄的代碼就是:
browser.find_element_by_xpath('//*[@id="J_SiteNavLogin"]/div[1]/div[1]/a[1]').click()
找到登錄元素位置,然後 click() 點擊。
點擊登錄後,進入登陸頁面,找到賬號框和密碼框位置,並輸入賬號和密碼。
還是簡單粗暴的複製粘貼 XPath 即可。
browser.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys(username)
browser.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys(password)
username 和 password 就是你要輸入的賬號和密碼。
輸入完密碼之後,可能會出現一個驗證碼滑動窗口。
這種滑動窗口也好解決,還是複製 XPath 匹配元素,然後使用 Selenium 的 ActionChains 方法,拖動滑塊。
最後點擊登陸按鈕。
登陸後,再讀取下用戶名,看下是否登陸成功即可。
分析完畢,直接上代碼。
from selenium import webdriver
import logging
import time
from selenium.common.exceptions import NoSuchElementException, WebDriverException
from retrying import retry
from selenium.webdriver import ActionChains
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class TaoBao(object):
def __init__(self):
super(TaoBao, self).__init__()
# self.browser = webdriver.Chrome("path\to\your\chromedriver.exe")
self.browser = webdriver.Chrome()
# 最大化窗口
self.browser.maximize_window()
self.browser.implicitly_wait(5)
self.domain = 'http://www.taobao.com'
self.action_chains = ActionChains(self.browser)
def login(self, username, password):
while True:
self.browser.get(self.domain)
time.sleep(1)
# 會xpath可以簡化這幾步
# self.browser.find_element_by_class_name('h').click()
# self.browser.find_element_by_id('fm-login-id').send_keys(username)
# self.browser.find_element_by_id('fm-login-password').send_keys(password)
self.browser.find_element_by_xpath('//*[@id="J_SiteNavLogin"]/div[1]/div[1]/a[1]').click()
self.browser.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys(username)
self.browser.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys(password)
time.sleep(1)
try:
# 出現驗證碼,滑動驗證
slider = self.browser.find_element_by_xpath("//span[contains(@class, 'btn_slide')]")
if slider.is_displayed():
# 拖拽滑塊
self.action_chains.drag_and_drop_by_offset(slider, 258, 0).perform()
time.sleep(0.5)
# 釋放滑塊,相當於點擊拖拽之後的釋放鼠標
self.action_chains.release().perform()
except (NoSuchElementException, WebDriverException):
logger.info('未出現登錄驗證碼')
# 會xpath可以簡化點擊登陸按鈕
# self.browser.find_element_by_class_name('password-login').click()
self.browser.find_element_by_xpath('//*[@id="login-form"]/div[4]/button').click()
nickname = self.get_nickname()
if nickname:
logger.info('登錄成功,呢稱爲:' + nickname)
break
logger.debug('登錄出錯,5s後繼續登錄')
time.sleep(5)
def get_nickname(self):
self.browser.get(self.domain)
time.sleep(0.5)
try:
return self.browser.find_element_by_class_name('site-nav-user').text
except NoSuchElementException:
return ''
if __name__ == '__main__':
# 填入自己的用戶名,密碼
username = 'username'
password = 'password'
tb = TaoBao()
tb.login(username, password)
代碼加了一些異常處理,以及 log 信息的打印。這裏需要注意的是,滑塊不是每次都出,所以要加個判斷。
輸入你的賬號和密碼,指定 Chrome 驅動路徑,運行代碼,看看能否如我們所願的登陸成功。
可以看到,賬號密碼,都輸入了,驗證碼也通過。
但是,就是登陸不上!這是爲什麼呢?
2.淘寶反 Selenium 登陸破解
很簡單,淘寶有反爬蟲,而且是專門針對 Selenium 的。這麼操作,永遠登陸不進去。遇到這種反爬的時候,不要慌,慢慢思考。通常,遇到這種反爬蟲,第一反應就是:驗證碼滑塊滑地太快了。被檢測出來了。我剛開始也是這麼想,所以我自己寫了一個滑動方法。勻速、加速、減速,甚至顫顫巍巍滑動,都不行!顯然,跟驗證碼滑塊無關。這時候,就得學會測試,分析出它的放爬蟲策略。分步測試,你就會發現,賬號密碼程序輸入,滑塊程序滑動,然後暫停程序,我們手動鼠標點擊登錄,就能登陸成功。神奇吧?這是爲啥?我猜測,應該是淘寶,有針對 Selenium 的 find_element_by_* 方法的 click 事件監聽。只要是使用 Selenium 完成的點擊事件,淘寶就不讓你登錄。
具體怎麼實現的我不清楚,但是我知道怎麼破解。
很簡單,Selenium 這個點擊方法不行,那就換個第三方庫唄!
Python 最不缺的就是各種各樣的第三方庫。
pyautogui 瞭解一下。pyautogui 功能強大,可以操控電腦的鼠標,有類似「按鍵精靈」的功能。pyautogui 的有些方法,甚至比「按鍵精靈」更強大。
安裝方法也很簡單,使用 pip 即可。
python -m pip install pyautogui
用法很簡單,截取登錄按鈕那裏的圖片,像這樣:
然後 pyautogui 就可以根據這張圖片,找到按鈕的座標,然後操控電腦的鼠標進行點擊。
coords = pyautogui.locateOnScreen('1.png')
x, y = pyautogui.center(coords)
pyautogui.leftClick(x, y)
就問你強大不?直接修改代碼,開搞!
from selenium import webdriver
import logging
import time
from selenium.common.exceptions import NoSuchElementException, WebDriverException
from retrying import retry
from selenium.webdriver import ActionChains
import pyautogui
pyautogui.PAUSE = 0.5
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class TaoBao(object):
def __init__(self):
super(TaoBao, self).__init__()
# self.browser = webdriver.Chrome("path\to\your\chromedriver.exe")
self.browser = webdriver.Chrome()
# 最大化窗口
self.browser.maximize_window()
self.browser.implicitly_wait(5)
self.domain = 'http://www.taobao.com'
self.action_chains = ActionChains(self.browser)
def login(self, username, password):
while True:
self.browser.get(self.domain)
time.sleep(1)
# 會xpath可以簡化這幾步
# self.browser.find_element_by_class_name('h').click()
# self.browser.find_element_by_id('fm-login-id').send_keys(username)
# self.browser.find_element_by_id('fm-login-password').send_keys(password)
self.browser.find_element_by_xpath('//*[@id="J_SiteNavLogin"]/div[1]/div[1]/a[1]').click()
self.browser.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys(username)
self.browser.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys(password)
time.sleep(1)
try:
# 出現驗證碼,滑動驗證
slider = self.browser.find_element_by_xpath("//span[contains(@class, 'btn_slide')]")
if slider.is_displayed():
# 拖拽滑塊
self.action_chains.drag_and_drop_by_offset(slider, 258, 0).perform()
time.sleep(0.5)
# 釋放滑塊,相當於點擊拖拽之後的釋放鼠標
self.action_chains.release().perform()
except (NoSuchElementException, WebDriverException):
logger.info('未出現登錄驗證碼')
# 會xpath可以簡化點擊登陸按鈕,但都無法登錄,需要使用 pyautogui 完成點擊事件
# self.browser.find_element_by_class_name('password-login').click()
# self.browser.find_element_by_xpath('//*[@id="login-form"]/div[4]/button').click()
# 圖片地址
coords = pyautogui.locateOnScreen('./1.png')
x, y = pyautogui.center(coords)
pyautogui.leftClick(x, y)
nickname = self.get_nickname()
if nickname:
logger.info('登錄成功,呢稱爲:' + nickname)
break
logger.debug('登錄出錯,5s後繼續登錄')
time.sleep(5)
def get_nickname(self):
self.browser.get(self.domain)
time.sleep(0.5)
try:
return self.browser.find_element_by_class_name('site-nav-user').text
except NoSuchElementException:
return ''
if __name__ == '__main__':
# 填入自己的用戶名,密碼
username = '淘寶用戶名'
password = '淘寶密碼'
tb = TaoBao()
tb.login(username, password)
運行效果: