赞
踩
作者的自言自语:我们在获取网页数据的时候,遇到某些网站往往需要登陆成功后才有我们想要的数据,这个时候我们就需要获得网页的cookie,如果每次都要自己打开网页复制cookie出来保存那太麻烦啦,所以我用selenium自动打开网页模拟。
我们要干的事情
1.selenium模拟打开网页,输入用户名,密码
2.登陆成功后获取cookie,保存为json
3.scrapy利用保存好的json读取cookie,爬取网页信息
Selenium作为python的一个网页模拟,可以操作众多的网页类型,这里我使用的chromedriver作为演示。需要条件
1.google浏览器
2.chromedriver.exe
我们来实战,以登陆友盟为例:
# -*- coding:utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import os
import time
import json
import traceback
from selenium import webdriver
# 这个函数的意思是去试着寻找指定的元素 尝试200次,每次间隔一秒
def TryUntilFind(driver,element,findway='find_element_by_xpath',findTime=1):
time.sleep(0.5)
if findTime > 200:
return 'Can\'t find'
try:
func = 'driver.%s(element)'%findway
return eval(func)
except Exception as e:
time.sleep(0.5)
return TryUntilFind(driver,element,findway,findTime+1)
# 启动google浏览器,自动登录友盟
def UmengLogin(username,password):
tmp_time = time.time()
driver = webdriver.Chrome()
# pass
result = u'error: --刚开始启动--'
try:
# 打开友盟的登陆网站
driver.get('https://i.umeng.com/')
time.sleep(0.5)
# 找到用户名输入框,输入用户名
TryUntilFind(driver,'//*[@id="ump"]/div[1]/div/form/div[1]/ul/li[1]/div/label/input').send_keys(username)
# 找到密码输入框 输入密码
TryUntilFind(driver,'//*[@id="ump"]/div[1]/div/form/div[1]/ul/li[2]/label/input').send_keys(password)
# 点击登陆
TryUntilFind(driver,'//*[@id="submitForm"]').click()
time.sleep(0.5)
# 检验是否登陆成功,成功后会跳转到指定网页,根据网页url是否转变了来判断
if driver.current_url != r"https://i.umeng.com/user/products":
time.sleep(1)
if driver.current_url != r"https://i.umeng.com/user/products":
raise Exception(u'登陆失败')
# 登陆成功后再随意打开个这个网页的子页面 就可以收集cookie了
driver.get('http://mobile.umeng.com/apps/get_summary_data')
time.sleep(0.5)
cookie = [item["name"] + "=" + item["value"] for item in driver.get_cookies()]
cookiestr = ';'.join(item for item in cookie)
# 我保留了三个字段 执行用的总时间-usetime 获取的cookie-cookie 现在的时间-now
result = {'usetime':str(time.time()-tmp_time),'cookie':cookiestr,'now':time.time()}
except Exception, e:
traceback.print_exc(file=open(os.path.join(sys.path[0],'err.txt'),'w'))
err = open('err.txt').read()
result = 'error: '+err
finally:
driver.quit()
return result
if __name__ == '__main__':
username = u'用户名'
password = u'密码'
result = UmengLogin(username,password)
if 'error:' not in result:
json.dump(result,open('umeng.json','wb'))
else:
# 如果有错误 报出错误
print(result)
可能遇到的错误
1.提示找不到chromedriver那么就去,错误所提示的网站下载最新版的chromedriver驱动,放置到环境变量Path有配置的位置,我的定制环境也有放置一个chromedriver.exe 放在Python27\Scripts里面
2.如果你简单的使用driver.get(‘xxx网站’)的时候网页崩溃了,那么估计是你的chromediver版本过低找个合适的就好了
3.如果用户名密码错误,那么你该检验下自己有没有自己可以登陆使用的账户了
简单解释一下上面的代码: 使用Selenium的webdriver模块可以启动google浏览器(driver = webdriver.Chrome())–打开指定网页(driver.get(网页地址))–找到账户密码输入框(driver.find_element_by_xpath(‘怎么获取是吧,浏览器右键你想找的元素-检查-Copy Xpath就找到了’))-登陆成功后再随便打开一个子页面,这时候网页的cookie就能用了
打开友盟网页 随便打开一款我们的产品
通过network的监控,我们会发现 自定义事件的所有数据都是通过一个网页接口请求得到的
So:,后面我们打算不登录友盟了,我们全部数据可以通过这个接口直接查询不就可以了得到了
右键Copy as cURL(bash)
把复制得到的curl保存为到txt,通过比较两款不一样的产品的curl可以发现,不同产品之间的差别只有
curl 'http://mobile.umeng.com/apps/628100426be85e76a38f0955/events/load_table_data?page=1&per_page=30&versions%5B%5D=&stats=count&show_all=false'
网页链接apps/~/events中间值的区别,这个值通过前一个页面-应用列表就可以得到我们所有产品的app-id
so:如果我们要查询我们所有产品的自定义事件,先在http://mobile.umeng.com/apps?show_all=true 获取所有产品的appid,然后通过拼接curl就可以查询所有数据啦,怎么获取我们所有产品呢?
方法一:通过Selenium遍历所有页面,把信息存进表里记录下来
方法二:分析这个show_all网址,发现所有的产品数据都是通过一个请求就全部获取了,保存这个curl,以后都这么获取所有产品的列表
我们把curl做成一个模板,原app-id用Replace_App_Id替换,原cookie用Replace_Cookie替换,保存为tmple.txt
curl 'http://mobile.umeng.com/apps/Replace_App_Id/events/load_table_data?page=1&per_page=30&versions%5B%5D=&stats=count&show_all=false' -H 'Cookie: Replace_Cookie' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'X-CSRF-Token: cOZgtNh6TDw+PHC/ClrbrkySOdKEcNbrqrCslHK5J/k=' -H 'Accept-Language: zh-CN,zh;q=0.8' -H 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0' -H 'Accept: application/json, text/javascript, */*; q=0.01' -H 'Referer: http://mobile.umeng.com/apps/Replace_App_Id/events/dashboard' -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' --compressed
这就是一个curl模板
接下来我们要指定appid查询数据
# -*- coding:utf-8 -*-
import os
import json
cookie_dic = json.load(open('umeng.json'))
tmple = open('tmple.txt').read()
tmple = tmple.replace('Replace_App_Id','628100426be85e76a38f0955')
curl = tmple.replace('Replace_Cookie',cookie_dic['cookie'])
print curl
怎么验证打印出来的这个curl能不能用呢?
mac电脑可以直接在终端输入这个curl就可以查询到数据了,由于我用的是Windows电脑所以只能借助其它linux电脑来查询,这里我用的Xshell,使用Xshell链接上我的mac电脑
从图中可以发现,通过替换appid和cookie值可以查询到准确的数据
但是如果我就是用的Windows电脑不想换了,我想直接代码查询呢?
可以通过python的paramiko模块,远程登录linux服务器得到,那么就省得开Xshell了
# -*- coding:utf-8 -*-
def create_ssh(username, password, ip, port=22):
"""
创建ssh连接
:param username: 用户名
:param password: 密码
:param ip: ip地址
:param port: 端口
:return: ssh连接客户端
"""
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, port, username, password)
return ssh
def usecmd(ssh_client, code):
# 在远程终端执行命令
stdin, stdout, stderr = ssh_client.exec_command(
"""
%s
"""%(code))
return stdout.read(), stderr.read()
if __name__ == '__main__':
IP_Port = 'linux电脑的ip地址'
ssh = create_ssh('linux电脑用户名','linux电脑密码',IP_Port,打开的远程连接共享端口)
curl = "你的curl命令"
out,err = usecmd(ssh,
"""
%s
"""%curl)
ssh.close()
print(out)
print('--------------')
print(err)
同理的,我们的产品数也会每天在增加,所以我们只需要Selenium获取cookie这个方法放在一台固定的机子上(我就放在我的常年开机的mac上的django),然后拼接获取到的cookie和获取所有产品的curl就能得每天
So: cookie是会有过期时间的,这就是为什么我前面讲到用Selenium自动获取cookie,并记录了一个当时的时间-now,假设友盟的过期时间为1小时,那么下次我获取cookie的时候就用当时的时间-now,如果>3600秒那么重新获取cookie,否则直接用已经获取的cookie
![enter description here][6]
所以现在我们做到了
1.通过Selenium获取cookie
2.在应用列表页面找到查询我的应用列表的接口,保存curl bash,并改造为模板,方便替换cookie查询我的所有应用
3.通过第二步我已经获得了所有应用的appid,在点击我的随意一款应用,查询自定义事件,保存curl bash,并改造为模板,通过替换appid和cookie就可以查询得到我想要的自定义事件了
4.后面我们会介绍到django,也就是以上的操作都可以挂到一台服务器自动完成,你只需要访问开出来的接口等结果就可以了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。