You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
17 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 19http库如何批量下载在线内容解放鼠标
你好,我是尹会生。
在上节课我们学习了怎么使用“requests-html”库来批量下载图片这足以帮你应对大部分需要批量下载互联网资源的场景了。
但是除了批量下载这一典型场景外还有两种场景“requests-html”工具无法覆盖其中就包括一些网站的每日签到功能明明登录网站后点击一个按钮就能领到虚拟货币但是每次还要手动输入账户和密码再用鼠标点击领取按钮。相信已经学会了如何用Python访问网页的你早就想把签到进行自动化了吧。
那么今天我就以京东自动签到领金豆为例为你介绍一款比“requests-html”更加强大的浏览器工具“selenium”通过selenium我将带你实现自动化的用户登录和模拟鼠标点击功能。
## selenium的适用场景
我刚才也提到了在你把“requests-html”库应用到各种批量下载场景之后你会发现有两种场景下使用“requests-html”无法实现批量下载。
一种场景是有的网页为了防止你用工具下载会对下载工具进行检测。如果你的HTTP客户端不是浏览器那就不允许你访问该网站下的所有内容。
另一种场景是一些网页为了更好的交互性就使用了JavaScript脚本语言。而JavaScript脚本语言需要在浏览器运行才能获得服务器的数据。所以如果使用“requests-html”来获取这些数据的话你就必须再编写Javascript脚本。
基于这两种原因我们可以使用“selenium”来解决。这也正是为什么有了“requests-html”库之后我还要再带你学习“selenium”库。
它的实现原理通过“WebDriver”组件把Python与浏览器连接起来让Python来控制浏览器的行为向浏览器发送各种模拟用户操作的指令此时真实的浏览器会按照Python发的各种指令对服务器进行访问。
这样既可以解决网页加密的问题又避免了再编写Javascript脚本弥补了“requests-html”在批量下载场景中的缺憾。无论从操作的友好程度还是实现功能的简单程度上都要比“requests-html”强大。
那今天这节课我们就来学习如何使用“selenium”来实现自动签到。不过考虑到你是第一次接触“selenium”所以在学习实现方法之前我还是先来带你学习怎么安装和执行它。
## “selenium” 的安装与初次运行
“selenium”是基于“Webdriver”连接Python和浏览器的而“Webdriver”的组件比较多所以它的安装过程也要比一般的Python第三方库复杂一点。
考虑到你是第一次使用它我就把具体的安装步骤以及注意事项拆分成了5个步骤保证你能顺利安装并且能用它访问网页。
第一步根据浏览器版本来下载“Webdriver”。
由于“selenium”会通过“Webdriver”调用你当前电脑上的浏览器访问HTTP服务器所以必须找到和浏览器版本一致的“Webdirver”程序然后下载下来。
我这里以工作中最常用的Chrome浏览器为例首先要通过Chrome的“设置”—“关于”菜单查看浏览器的版本。我的Chrome浏览器版本如下图
![](https://static001.geekbang.org/resource/image/21/0c/211e46d304be4ec29709295396dbc70c.png)
接着根据我的浏览器版本“89.0”访问“Webdrive”[国内的镜像站](http://npm.taobao.org/mirrors/chromedriver/)下载与浏览器相匹配版本的“Webdriver”。这里要注意不同的操作系统“Webdriver”的安装包不同所以需要你选择对应的操作系统版本。“Webdriver”的下载网页内容截图如下
![](https://static001.geekbang.org/resource/image/72/e7/724055e74881a83f406fb4b777607be7.png)
我这里以“mac”操作系统为例下载了“chromedriver\_mac64.zip”压缩包后解压缩之后会得到“chromedriver”文件。这个文件就是连接Python和浏览器的工具。
第二步把“Webdriver”放在命令的搜索路径下。
“chromedriver”文件是一个可执行文件我们需要把它放入命令的搜索路径中这样文件才能在Python调用浏览器时被直接运行我们就不用输入它的完整路径。
我在这里解释一下命令的搜索路径。它是每个操作系统都事先定义好的,就像它的名字一样,你在命令行运行的任意一条命令,都可以从命令搜索路径中依次查找到。
那么在mac操作系统下我们可以使用命令行运行“echo $PATH”来查看当前系统的命令搜索路径都有哪些。
在这个命令行中变量“PATH”就是专门用于指定命令搜索路径的环境变量。我电脑上的命令搜索路径和搜索顺序如下。
```
SHELL$ echo $PATH
/Library/Frameworks/Python.framework/Versions/3.7/bin
:/usr/local/bin:/usr/bin
:/bin
:/usr/sbin
:/sbin
```
基于操作系统会按照上面的目录对命令进行搜索我可以把“chromedriver”放在上面的任意一个目录当中。不过我更推荐你把它放在Python相同的目录中便于你后续版本更新时对它进行文件替换。
我的Python安装目录是“/Library/Frameworks/Python.framework/Versions/3.7/bin”因此我就把“chromedriver” 放在这个目录中。放入之后我就可以在命令行运行“chromedirver”。如果能够正确运行则会提示运行成功。否则会提示找不到这条命令你需要再检查一下它被存放的目录。正确运行的截图如下供你参考。
![](https://static001.geekbang.org/resource/image/ca/9e/ca388b78ff7a7b2ae52bec099f78a99e.png)
在完成了最复杂的“Webdriver”安装之后接下来就可以安装Python的库并尝试使用Python库调用浏览器了。
第三步安装“selenium”库。
安装“selenium”库可以继续使用pip命令。它的库和安装包同名你可以在命令行运行以下命令进行正确安装。
```
pip3 install selenium
```
第四步使用“selenium”访问网页。
安装成功之后我们可以通过任意一个网页的访问来测试从Python到“Webdriver”再到浏览器整个工具链是否能正确运行。我把代码贴在下方供你参考。
```
from selenium import webdriver
import time
browser = webdriver.Chrome()
browser.get("http://www.jd.com")
time.sleep(10)
browser.quit()
```
这段代码实现了调用浏览器访问京东的网页并在10秒后自动关闭浏览器的功能。如果能够正确运行那么说明整个工作链是配置正确的。
这段用来访问京东来验证工作链的代码,由**导入库、浏览器的初始化、控制浏览器行为**三个部分组成。我来解释一下。
**首先是导入库。**我在代码的前2行除了导入“selenium”库用来调用“Webdriver”外还导入了“time”库。
导“time”库的原因就在于我们需要使用“selenium”库模拟手工操作浏览器的流程而手工操作会有一定的延迟。所以我就基于“time”库的“sleep()”函数来模仿用户查看网页的行为在打开网页等待了10秒后再关闭网页。
**其次是浏览器的初始化。**浏览器的初始化在Python内部做了两件事情第一个是找到之前安装的“chromedriver”文件检查它是否可执行。第二件事情是根据调用的“Chrome()”函数,找到当前电脑中的浏览器并运行它。
**最后控制浏览器的行为**。我使用了“get()和quit()”两个函数它们分别实现的是向服务器发起HTTP的“GET”请求以及关闭浏览器的功能。
请求如果成功发送, 你会在“Webdriver”打开的浏览器看到网页内容我把正确执行的结果截图放在下面供你参考。
![](https://static001.geekbang.org/resource/image/bc/43/bc0cc885646c5e26c3b1ced7e03b7443.png)
**第五步,****取得网页的源代码并打印。**
通过“selenium”打开浏览器之后除了控制浏览器的行为你还需要像上一讲的批量下载图片一样批量获取网页的资源。这时你可以使用如下代码来获取当前浏览网页的源代码。这样在关闭浏览器之后你仍然可以对网页的内容进行操作。代码如下
```
content = browser.page_source
print(content)
```
掌握了“selenium”和“Webdriver”的安装和运行接下来我们就可以利用“selenium”来实现京东的自动签到功能了。通过这一场景来为你演示如何通过“selenium”模拟浏览器并实现自动签到。
## 如何实现京东自动签到
要想实现自动签到你既要实现用户登录又要模拟用户点击按钮。随着技术的日新月异很多登录和按钮都不再使用简单的“POST”请求了。这时你就需要用“selenium”基于标签名字找到按钮的链接像普通用户请求网站链接一样不必理解登录和签到的内部的原理就能实现自动化访问。
### 自动签到的原理与思路
“selenium”之所以能替代手动操作达到自动化的效果核心原因在于我们可以通过“selenium”来模拟浏览器的操作。而我们可以通过对浏览器的功能拆解把浏览器的交互行为一一对应到“selenium”的非交互命令之后就能实现自动化操作了。
这也正是自动签到的原理。再进一步说“selenium”的行为越像浏览器自动签到的功能就模拟得越完整。换言之签到功能也就更自动化。那我们就来看看浏览器是如何实现登录和签到工作的。
使用浏览器进行登录有三个步骤,分别为:
1. 打开登录页面;
2. 切换到用户密码登录选项卡;
3. 点击登录按钮。
我们依次来分析一下这三个步骤如果用“selenium”各自是怎么实现的。
首先打开登录页面在浏览器中是鼠标点击“登录”按钮实现的它的实现是向指定的URL发送“GET”请求发送后服务端返回网页就是你见到的登录页面了。
其次,打开登录页面后,默认的登录方式是二维码登录。
为了能让“selenium”能够模拟我们需要通过用户名和密码方式登录。那接下来就切换到用户密码登录这一选项卡这一切换动作在浏览器中可以通过使用鼠标实现。不过在“selenium”中我们需要通过“GET”请求来替代它才能实现非交互式的登录。
登录切换页面的网页源代码以及网页,我把相关截图一并放在下方,供你参考。
![](https://static001.geekbang.org/resource/image/fb/31/fbde90ae5cacc859ac05d09b63159a31.png)
最后,你需要在浏览器输入用户名密码,而后点击“登录”按钮,实现登录。
由于京东的登录界面是经过加密的所以不能使用“requests-html”直接发送“POST”请求来实现登录这里仍然要继续使用“selenium”获取用户名、密码的输入框输入之后模拟点击按钮的“GET”请求到服务器之后才能实现登录。
### 使用“selenium”模拟浏览器实现自动登录
在了解了浏览器的原理之后你就可以使用“selenium”模拟浏览器实现登录了。我把“selenium”登录京东的代码写在下方供你参考。
```
from selenium import webdriver
import time
browser = webdriver.Chrome()
# 访问主页
browser.get("http://www.jd.com")
time.sleep(2)
# 访问登录页
browser.get("https://passport.jd.com/new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F")
time.sleep(2)
# 切换为用户密码登录
r = browser.find_element_by_xpath(
'//div[@class="login-tab login-tab-r"]')
browser.execute_script('arguments[0].click()', r)
time.sleep(2)
# 发送要输入的用户名和密码
browser.find_element_by_xpath(
"//input[@id='loginname']").send_keys("username")
time.sleep(1)
for i in "password":
browser.find_element_by_xpath(
"//input[@id='nloginpwd']").send_keys(i)
time.sleep(1)
# 点击登录按钮
browser.find_element_by_xpath(
'//div[@class="login-btn"]/a').click()
time.sleep(10)
# 退出浏览器
browser.quit()
```
我在代码中为了模拟浏览器的登录行为一共使用了5个函数每个函数都对应着“selenium”的一种操作。按照代码的运行顺序我分别使用了请求网页、使用XPath查找标签、执行脚本、模拟键盘输入以及模拟鼠标点击五个动作来实现登录的模拟操作。接下来我们先从请求网页开始来为你逐个分析这五个函数。
第一个函数get() 使用“GET”方式请求网页。当你需要点击超链接来到达新的页面时都可以使用“get()”函数来实现。所以在代码中,请求主页和请求登录页面都是用了这个函数。
第二个函数find\_element\_by\_xpath() 。在网页中你需要对某一标签进行操作时可以使用“XPath”先找到该标签。类似地在浏览器中“find\_element\_by\_xpath() ”就是找到你想操作的标签。
比如我在代码中找到用户名和密码的选项卡、用户名密码的输入框、登录按钮等元素都是用过它进行定位的。定位的方法和上节课讲的方式相同通过浏览器的调试页面找到网页元素对应的代码再把代码利用“XPath”提取出来即可。
第三个函数execute\_script() 是用来执行网页中自带的JavaScript脚本的。当你切换用户密码选项卡时会发现网站的代码是用JavaScript来实现的而你又不想再去手动编写脚本执行“class”属性为“login-tab login-tab-r”的“div”标签下面的JavaScript脚本那就可以使用这个函数对第一个参数的JavaScript进行点击。
第四个函数send\_keys()用于在输入框填写内容。我在脚本中把“username”和“password”作为用户名和密码自动填入输入框中你可以把它们替换为真正的用户名和密码。
这里需要注意的是,我对密码的填入增加了间隔时间,否则登录时会弹出图形验证码,阻止你进行自动登录。
第五个函数click() 用于模拟鼠标点击超链接的动作它和取得超链接中的href属性并用“GET”方式访问是相同的功能但是“click()”函数会比“get()”函数更直接减少了从“a”标签再提取“href”属性的麻烦。
以上就是使用“selenium”模拟浏览器实现登录的主要思路。登录之后我们想要实现签到的障碍就全都解决了。那么接下来我来带你继续实现自动签到功能。
### 利用“selenium”实现自动签到
要想实现自动签到还需要访问签到页面和点击签到按钮。这两个功能相信你在我为你分析了登录的代码之后一定会想到访问页面可以使用“get()”函数签到按钮可以使用“click()”函数。
我把自动签到的代码放在下面一并提供给你。通过和登录代码的整合你就可以利用“selenium”实现自动签到的功能了。
```
# 访问签到页面
browser.get("https://mall.jd.com/index-1000002826.html")
time.sleep(2)
# 签到并领金豆
browser.find_element_by_xpath('//div[@class="jSign"]/a').click()
time.sleep(10)
```
这段代码就是访问签到页面并领取金豆的代码。需要你注意的是,访问页面和签到两个操作之间需要等待几秒,否则会因为网页加载过慢,导致签到按钮还没加载完就发送了点击动作,让自动签到失败。
## 总结
最后我来为你总结一下本节课的主要内容。在这一讲中我通过“selenium”实现了浏览器的模拟并把浏览器的点击链接、用户登录、切换标签等常用功能使用“selenium”的函数和XPath转换为用Python可以控制的操作。转换之后你就可以利用Python控制浏览器的行为把这些需要鼠标的交互式操作编写为非交互式的代码达到自动化控制浏览器的目的了。
除了实现自动签到以外通过“selenium”的函数组合你就能模拟浏览器的绝大部分操作。我也希望你能够在学完这节课后想一想你的工作当中是否也使用了浏览器进行重复的工作希望你能通过对本讲的学习把它们改为自动化。
## 思考题
按照惯例最后我来为你留一道思考题你能否利用今天讲的模拟浏览器的方法自动登录Github并以“Python”作为关键字进行搜索然后把搜索的结果保存到一个文件呢
欢迎把你的想法和思考分享在留言区,我们一起交流讨论。也欢迎你把课程分享给你的同事、朋友,我们一起做职场中的效率人。我们下节课再见!