本文 GitHub https://github.com/Jack-Cherish/PythonPark 已收录,有技术干货文章,整理的学习资料,一线大厂面试经验分享等,欢迎 Star 和 完善。css
爬虫系列,已讲 5 篇。html
文字、图片、视频这类常规的内容下载、API 的使用,这些操做对你来讲,应该垂手可得了。python
那今天,就讲解一下高级一点的技能,「模拟登陆」。git
值此 618 之际,帮他/她清空一波购物车!github
学爬虫,总能听到「模拟登陆」这四个字,究竟什么是「模拟登陆」?web
通俗一点讲,「模拟登陆」就是程序用帐号和密码自动登陆一个网站。面试
而后,拿到只有登陆后,才能下载的网站数据。算法
好比,咱们只有登陆淘宝帐号以后,才能看到购物车里有哪些东西。chrome
本文,就以「模拟登陆」淘宝为例进行讲解,并帮他/她清空购物车。浏览器
你只须要知道他/她的淘宝帐号和密码,而且有个充足的钱包,就能够运行程序,扫码支付一鼓作气。
体验自动结算,钱包秒空的快感!
模拟登陆无非两种方法:请求包分析模拟登陆、自动化测试工具模拟登陆。
前者,须要抓包分析请求,解析各类参数,还可能涉及一些加密算法。
后者,能够绕过一些繁琐的分析过程,直接定位元素进行操做,但也会遇到一些反爬策略。
二者,都有各自的操做技巧。
以前的教程,讲解了不少基于 requests 请求包分析的爬虫思路。
本文讲解一个新思路,使用自动化测试工具 Selenium 模拟登陆。
Selenium 基本的使用方法,以及如何破解淘宝对于 Selenium 的反爬策略,尽在下文。
Selenium 是一个自动化测试工具,支持各类主流浏览器,例如 Chrome、Safari、Firefox 等。
不知道什么是自动化测试工具不要紧,我会经过实战操做,慢慢讲解。
无论怎样,先安装 Selenium 再说。
pip install selenium
使用 pip 直接安装 selenium。
除了安装 Python 的 Selenium 第三方库,还须要根据浏览器配置相应的浏览器驱动。
以 Chrome 为例,下载浏览器驱动。
驱动下载地址(需翻墙):点击查看
须要根据浏览器的版本,选择驱动下载。
没法翻墙下载不要紧,我已经将这三个版本的驱动下载并上传到百度云了。
百度云连接:https://pan.baidu.com/s/1-AfONQGkK8xPwLaW5P-9Bw
提取码:cbsu
使用 Selenium 登陆百度看一下。
from selenium import webdriver if __name__ == "__main__": browser = webdriver.Chrome('path\to\your\chromedriver.exe') browser.get('https://www.baidu.com/')
上面的 path\to\your\chromedriver.exe 是刚刚下载的 Chrome 驱动文件位置,根据本身的状况修改,建议使用绝对路径。结果以下图所示:
程序会自动打开 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.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)
打开 www.python.org 官网,并根据 name 属性为 q 找到搜索框,并输入 pycon 并点击搜索。
运行结果:
写好程序,浏览器自动操做,是否是很简单,很酷炫?
这就是自动化测试工具,程序写好,浏览器自动执行你的写的操做。
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.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 的基础知识,能够看下我 3 年前写的文章。
文章地址:点击查看
详细的,关于 Selenium 的 API 文档,能够看官方手册。
官方手册:点击查看
好了,基础知识准备完毕。
只要你会使用 copy xpath,基本的 Selenium 操做,就能够开始跟我一块儿「模拟登陆」淘宝。
这场为了爱情的清空购物车大做战,须要分两步完成:
用 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(): def __init__(self): self.browser = webdriver.Chrome("path\to\your\chromedriver.exe") # 最大化窗口 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 驱动路径,运行代码,看看可否如咱们所愿的登录成功。
能够看到,帐号密码,都输入了,验证码也经过。
可是,就是登录不上!这是为何呢?
很简单,淘宝有反爬虫,并且是专门针对 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(): def __init__(self): self.browser = webdriver.Chrome("path\to\your\chromedriver.exe") # 最大化窗口 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 = 'username' password = 'password' tb = taobao() tb.login(username, password)
淘宝针对 Selenium 的反爬,就这样解决了!
已经登录进来了,清空购物车就小菜一碟了!
仍是按照以前的步骤,自行分析吧。
这里很简单,我就直接贴代码了。
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(): def __init__(self): self.browser = webdriver.Chrome("path\to\your\chromedriver.exe") # 最大化窗口 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 '' def clear_cart(self): cart = self.browser.find_element_by_xpath('//*[@id="J_MiniCart"]') if cart.is_displayed(): cart.click() select = self.browser.find_element_by_xpath('//*[@id="J_SelectAll1"]/div/label') if select.is_displayed(): select.click() time.sleep(0.5) go = self.browser.find_element_by_xpath('//*[@id="J_Go"]') if go.is_displayed(): go.click() submit = self.browser.find_element_by_xpath('//*[@id="submitOrderPC_1"]/div/a[2]') if submit.is_displayed(): submit.click() if __name__ == '__main__': # 填入本身的用户名,密码 username = 'username' password = 'password' tb = taobao() tb.login(username, password) tb.clear_cart()
运行效果:
剩下的就是掏钱了。
扫码支付,只要你有钱,你甚至能够不看价格,直接程序写好支付密码,完成支付。
点赞再看,养成习惯,微信公众号搜索【JackCui-AI】关注一个在互联网摸爬滚打的潜行者