2017-9-17 22:33:54 [显示全部楼层]
5560浏览
查看: 5560|回复: 6

在Hikey开发板上用LED闪烁及蜂鸣器提醒论坛新回复(一)

[复制链接]

前言

最近学习Python模拟登陆相关的东西,副产品就是样。

效果:定时登陆DFRobot并查询是否有人回复,有则led闪烁+蜂鸣器响。

硬件:Lemaker Hikey 开发板;LED module;Buzzer module;杜邦线若干。

软件环境:windows 7 x64;Archlinux|Raspbian;Python3;phantomjs;Fiddler;Chrome

1、基础知识

​        之前在我的inoreader订阅里读到这么一篇文章:手机APP自动签到—python实现,既往只用过Python+RPi.GPIO库去控制树莓派的引脚,现在发现了Python的其他有趣的应用如Web、神经网络、大数据之类,求知若渴。

​          通过上述文章,了解到Fiddler这款软件和requests库。断断续续学了很多,知乎、微信公众号上面一大堆,一直不得入门,这次突发奇想(懒癌发作)用手头的Lemaker Hikey自动模拟登录DFRobot论坛,然后定时查看一下有木有新提醒,有的话就发微信 OR 邮件通知我。

说干就干,建议在此之前先阅读以下文章:

看不太懂没关系,大致有个概念就行。此外文中介绍的方法有些已经失效,但是看完作者的文章,再阅读作者的开源项目smart_login代码,相信会和我一样有茅塞顿开,醍醐灌顶之感。

一般来说:

  1. Fiddler/HTTPanalyzer/Charles用来抓包,了解正常登陆流程
  2. Chrome调试工具用来查看网络资源
  3. phantomjs等无界面浏览器用来模拟真实登陆
  4. selenium结合Python用来操作phantomjs浏览器(建议以后直接操作更高效)
  5. reuqests包用来模拟发送包

2、 分析DFRobot网站登陆

看完上述的文章,稍微上手之后,我们来看看df网站如何登陆的。使用fiddler抓包:

可以看到登陆过程中每次response都会改动cookies(安装Privacy scanner拓展可以看到),而且用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下进行演示。开发环境配置包括以下步骤:

  • 下载安装最新版Python3
  • 安装相关依赖库:python -m pip install lxml selenium
  • 下载安装phantomjs,记住安装路径如D:\Program Files (x86)\phantomjs\bin\phantomjs.exe
  • 配置编辑器,以Visual Studio Code为例。Ctrl+Shift+X安装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[starts-with(@id, "username_")]')
    self.account.clear()
    self.account.send_keys(self.account_num)

    self.passwd = self.driver.find_element_by_xpath('//input[starts-with(@id, "password3_")]')
    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以及selenium 总结篇,常见方法和页面元素的操作
  • 象征性的加个headers,其实df登陆不需要指定headers。一般我们需要设置User-AgentRefer(防盗链)
  • phantomjs的路径前要加r表示转义,参考WebDriverException: Message: 'phantomjs.exe' executable needs to be in PATH.,linux和windows路径分别用\/,所以windows下要转义。
  • 输入框每次也会变,但是固定格式username_xxx,所以采用XPath模糊查找。参考XPath、XQuery 以及 XSLT 函数以及Selenium Webdriver元素定位的八种常用方式
  • 截图来验证登陆成功,正式代码可以注释掉。用完之后phantomjs要quit(),不然会一直后台运行。
  • 获取hash值,可以参考Python get value from input element with lxml xpath
  • Selenium支持的webdriver列表:http://docs.seleniumhq.org/projects/webdriver/ 。据说phantomjs载入保存的cookie文件时偶尔出错,所以推荐使用chrome或者firefox。
  • 不加路径的话,默认文件路径为运行目录,不一定为程序所在目录。

基本我踩过的坑都写在上面了。至此,我们使用python+selenium以及phantomjs获取了一次完整登陆的cookies文件。参考Selenium Webdriver传递Cookies给requests及持久化 ,requests库使用cookies的方法如下:

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是否正确。


d4b50e087bf40ad14465f93b5d2c11dfabecceb7.jpg

luna  初级技神

发表于 2017-9-18 10:12:17

感觉是来卖萌的
回复

使用道具 举报

Ash  管理员

发表于 2017-9-18 14:02:34

感觉是来卖萌的
回复

使用道具 举报

old_navy  学徒

发表于 2017-9-18 22:37:51

本帖最后由 old_navy 于 2017-9-18 22:40 编辑

这是一个测试回复X2
回复

使用道具 举报

pATAq  版主
 楼主|

发表于 2017-9-21 23:38:54

Ash 发表于 2017-9-18 14:02
感觉是来卖萌的

我更新啦
回复

使用道具 举报

pATAq  版主
 楼主|

发表于 2017-9-21 23:39:05

luna 发表于 2017-9-18 10:12
感觉是来卖萌的

我是来填坑的~
回复

使用道具 举报

luna  初级技神

发表于 2017-9-22 10:37:12

pATAq 发表于 2017-9-21 23:39
我是来填坑的~

这坑开的惊艳!真是为了登录论坛操碎了心~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail