在Hikey开发板上用LED闪烁及蜂鸣器提醒论坛新回复(一)
# 前言最近学习Python模拟登陆相关的东西,副产品就是样。
效果:定时登陆DFRobot并查询是否有人回复,有则led闪烁+蜂鸣器响。
硬件:Lemaker Hikey 开发板;LED module;Buzzer module;杜邦线若干。
软件环境:windows 7 x64;Archlinux|Raspbian;Python3;phantomjs;Fiddler;Chrome
## 1、基础知识
之前在我的(https://www.inoreader.com)订阅里读到这么一篇文章:[手机APP自动签到—python实现](http://www.361way.com/mobile-app-auto-sign/4661.html),既往只用过Python+RPi.GPIO库去控制树莓派的引脚,现在发现了Python的其他有趣的应用如Web、神经网络、大数据之类,求知若渴。
通过上述文章,了解到Fiddler这款软件和requests库。断断续续学了很多,知乎、微信公众号上面一大堆,一直不得入门,这次突发奇想~~(懒癌发作)~~用手头的Lemaker Hikey自动模拟登录DFRobot论坛,然后定时查看一下有木有新提醒,有的话就发微信 OR 邮件通知我。
说干就干,建议在此之前先阅读以下文章:
* (https://rookiefly.cn/detail/57)
* (https://rookiefly.cn/detail/65)
* [超详细的Python实现新浪微博模拟登陆(小白都能懂)](http://www.jianshu.com/p/816594c83c74)
* [超详细的Python实现百度云盘模拟登陆(模拟登陆进阶)](https://rookiefly.cn/detail/153)
看不太懂没关系,大致有个概念就行。此外文中介绍的方法有些已经失效,但是看完作者的文章,再阅读作者的开源项目(https://github.com/ResolveWang/smart_login/)代码,相信会和我一样有茅塞顿开,醍醐灌顶之感。
一般来说:
1. Fiddler/HTTPanalyzer/Charles用来抓包,了解正常登陆流程
2. Chrome调试工具用来查看网络资源
3. phantomjs等无界面浏览器用来模拟真实登陆
4. selenium结合Python用来操作phantomjs浏览器(建议以后直接操作更高效)
5. reuqests包用来模拟发送包
## 2、 分析DFRobot网站登陆
看完上述的文章,稍微上手之后,我们来看看df网站如何登陆的。使用fiddler抓包:

可以看到登陆过程中每次response都会改动cookies(安装(http://www.telerik.com/fiddler/add-ons)拓展可以看到),而且用chrome插件`EditThisCookie`可以看到cookie内容非常丰富,会包含登陆ip、登陆地址、上次登陆时间等等内容。登陆不需要验证码。

登陆时post的数据如上,有两个值:loginhash和formhash,每次登陆都会变。hash值不可能凭空生成,有三种可能情况:1 是藏在页面中的;2 是通过服务器返回的;3是通过运行javascript脚本生成的。我们通过chrome调试模式(F12)和搜索分析Fiddler会话之后认为该值是登陆时服务器返回的。

那么整个过程就比较清晰了:
**难点:**`hash`值以及复杂的cookies。
**解决思路:**phantomjs模拟登陆+保存cookies。
以上方案都是基于dfrobot登陆需要验证码的前提下,所以最初是研究怎么获得登陆后的cookies,后来发现不需要验证码,但是沿用了这一思路。其实直接用requests库登陆理论上也是可以的(解决hash值,post的时候要对应qd)
> 注意:如果使用手动输入网址进行抓包,每次一定要清理缓存,不然有的请求被缓存起来了,抓包是看不到的。
## 3、开始动工——登陆
我这里先以Windows下进行演示。开发环境配置包括以下步骤:
* 下载安装最新版(https://www.python.org/downloads/)
* 安装相关依赖库:`python -m pip install lxml selenium`
* 下载安装(http://phantomjs.org/download.html),记住安装路径如`D:\Program Files (x86)\phantomjs\bin\phantomjs.exe`
* 配置编辑器,以`Visual Studio Code`为例。`Ctrl+Shift+X`安装`python`拓展。
核心代码如下:
```python
# -*- coding: utf-8 -*-
__author__ = 'Code_Paintium'
# Date:2017-9-14
# Filename:DFRobot vLogin
from selenium import webdriver
import pickle, time, requests, pathlib
from lxml import etree
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class df_warmup():
# 用户名、密码登陆
def __init__(self, account_num, passwd_str):
self.account_num = account_num
self.passwd_str = passwd_str
self.url = 'https://mc.dfrobot.com.cn/member.php?mod=logging&action=login'
self.path = pathlib.Path('cookies.df')
self.proxies = {
"http": "http://127.0.0.1:8888"
}
self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
self.df = requests.session()
if not self.path.exists():
print('cookies not found, generating...')
self.GetCookies()
# 运行一次就会生成,防止死循环
# 调用phantomjs获取cookies:
def GetCookies(self):
self.driver = webdriver.PhantomJS(executable_path=r'D:\Program Files (x86)\phantomjs\bin\phantomjs.exe')
self.driver.get(self.url)
wait = WebDriverWait(self.driver, 10)
wait.until(EC.presence_of_element_located((By.NAME, "loginsubmit"))).click()
self.account = self.driver.find_element_by_xpath('//input')
self.account.clear()
self.account.send_keys(self.account_num)
self.passwd = self.driver.find_element_by_xpath('//input')
self.passwd.clear()
self.passwd.send_keys(self.passwd_str)
self.remember_me = self.driver.find_element_by_name('cookietime')
self.remember_me.click()
self.click_button = self.driver.find_element_by_name('loginsubmit')
self.click_button.click()
wait = WebDriverWait(self.driver, 10)
wait.until(EC.presence_of_element_located((By.XPATH, "//*[@id='pm_ntc']")))
pickle.dump(self.driver.get_cookies(), open("cookies.df", "wb"))
self.driver.save_screenshot("df.png")
self.driver.quit()
df = df_warmup('username', 'password')
df.GetCookies()
```
**相关知识:**
* 定义了一个类 df_warmup,但是发现直接面向过程编程更快。。。
* pickle模块用来`原样`保存cookies,和`file`不同。建议看看《A Byte of Python3(中文版)》中输入输出一节
* python3内置pathlib模块,这里用来判断cookies文件是否存在。当然也可以用其他方法
* lxml和更常用的BeautifulSoup库都是用来解析html文件,且lxml速度更快,支持XPath。这里用来查找返回的hash值。XPath可以在chrome中选中元素审查,右击复制。
* 登陆按钮点击过早可能网页还没完全加载,导致登陆失败。一种是载入`time`模块然后`time.sleep(5)`这种,另一种就是智能等待指定节点的指定属性加载完成,一般当登陆按钮的click属性加载完成就可以了,参考[常用Selenium代码整理及Tips](https://blog.yasking.org/a/selenium-somelog.html)以及(http://www.cnblogs.com/tobecrazy/p/4570494.html)
* 象征性的加个headers,其实df登陆不需要指定headers。一般我们需要设置`User-Agent`和`Refer`(防盗链)
* phantomjs的路径前要加r表示转义,参考(http://blog.csdn.net/sinat_36764186/article/details/55520444),linux和windows路径分别用`\`和`/`,所以windows下要转义。
* 输入框每次也会变,但是固定格式username_xxx,所以采用XPath模糊查找。参考(http://www.w3school.com.cn/xpath/xpath_functions.asp)以及(http://www.cnblogs.com/qingchunjun/p/4208159.html)
* 截图来验证登陆成功,正式代码可以注释掉。用完之后phantomjs要`quit()`,不然会一直后台运行。
* 获取hash值,可以参考(https://stackoverflow.com/questi ... ent-with-lxml-xpath) 。
* Selenium支持的webdriver列表:http://docs.seleniumhq.org/projects/webdriver/ 。据说phantomjs载入保存的cookie文件时偶尔出错,所以推荐使用chrome或者firefox。
* 不加路径的话,默认文件路径为运行目录,不一定为程序所在目录。
基本我踩过的坑都写在上面了。至此,我们使用python+selenium以及phantomjs获取了一次完整登陆的cookies文件。参考(https://blog.yasking.org/a/selenium-and-requests.html) ,requests库使用cookies的方法如下:
```python
import pickle
import requests
cookies = pickle.load(open("cookies.pkl", "rb"))
s = requests.session()
for cookie in cookies:
s.cookies.set(cookie['name'], cookie['value'])
```
我们可以get一下home主页,看看服务器返回内容来确定cookies是否正确。
感觉是来卖萌的{:5_168:} 感觉是来卖萌的{:5_196:} 本帖最后由 old_navy 于 2017-9-18 22:40 编辑
这是一个测试回复X2 Ash 发表于 2017-9-18 14:02
感觉是来卖萌的
我更新啦 luna 发表于 2017-9-18 10:12
感觉是来卖萌的
我是来填坑的~ pATAq 发表于 2017-9-21 23:39
我是来填坑的~
这坑开的惊艳!真是为了登录论坛操碎了心~{:5_148:}
页:
[1]