基于 requests 的全能扫描王爬虫实践
投稿人:Alan
摘要:全能扫描王是文件扫描留档的重要工具,本文利用requests爬虫将手机客户端的扫描文件,同步至电脑端。
一、背景
在审计工作中,需要大批量扫描文件留档,全能扫描王成为主流的手机端扫描工具。由于网页端的全能扫描王无法大批量下载的扫描文件,在一定的限制环境下,使用将手机端同步至电脑成为一大需求,本文利用requests爬虫下载扫描文件,tkinter设计交互界面,pyinstaller打包封装exe实现脱机使用。
二、Fiddler抓包
Fiddler安装及证书信任设置不在此赘述。
(1)user/login请求
利用火狐浏览器访问扫描王网页(https://www.camscanner.com/user/login
),并输入用户名和密码点击登录。在Fiddler中观察执行情况,发现第247号POST请求user/login
下webform包含上传参数,返回结果json为URL,且在Fiddler抓取的URL中已经访问(第249号),故应为跳转的网址(如图2-1)。
图2-1
(2)files/holder请求
该请求为登录后的界面,在Fiddler中仅执行请求返回为0,未获取登录后网页,故可能需要模拟请求头部和Cookie。在执行带header和cookie的请求后成功获取登录界面,其中cookie包含_csc、 _csl、Hm_lvt_8f0191b1f1b207d4f6e0d42e771d6fde、_oa、_cdn、 JSESSID、Hm_lpvt_8f0191b1f1b207d4f6e0d42e771d6fde、_ct、 _isus、 _cslt、 S2、 _cssu、_csste等参数。登录后的界面包含了用户已经同步至云端的所有文件列表,但请求结果中未发现文件清单的信息,故猜测可能存在别的网址。在Fiddler抓取结果中,发现图2-1中第270号请求中返回文件列表(如图2-2)。
图2-2
(3)doc/list请求
该请求获取文件列表,在Fiddler中执行带header和cookie的doc/list请求,结果与抓取一致。
(4)doc/downloadpdf请求
在火狐浏览器中下载某一个文件,Fiddler中发现请求doc/downloadpdf
和stat/download
与下载相关,其中doc/downloadpdf
根据提供的文件的唯一标识doc_id返回对应的下载地址(如图2-3),而stat/download
是确认文件下载状态,故主要关注doc/downloadpdf
请求。
图2-3
三、requests爬虫实现
在第二节的抓包后,着手进行代码实现,考虑到程序为工作的需求,故脱离python环境也能执行,故暂不考虑selenium,而采用requests。程序主要分为登录(login_page
)、获取文件列表(get_file_list
)、下载文件(get_downloadfile_url_one
)三块。
(1)程序初始化
设置requests.session、headers等变量,并应用logger包将在程序中打log,代码如下:
class downloadscan(object): def __init__(self,username,password): self.session = requests.session() self.url = "https://www.camscanner.com/user/login" self.username,self.password =username,password self.respage = None self.headers = {"Host": "www.camscanner.com",\ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0",\ "Accept":"text/plain, */*; q=0.01",\ "Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",\ "Accept-Encoding":"gzip, deflate, br",\ "Content-Type": "application/x-www-form-urlencoded",\ "X-Requested-With":"XMLHttpRequest",\ "Connection":"keep-alive",\ "Cache-Contro":"max-age=0, no-cache",\ "Pragma":"no-cache"} self.file_list = None self.tmp_cookie = None self.download_res = {"filename":None,"address":None} self.status = True self.logger = logging.getLogger(__name__) self.logger.setLevel(level = logging.INFO) handler = logging.FileHandler("./camscanner/log/log") handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) self.logger.addHandler(handler)
(2)登录login_page
利用requests.session.post
实现user/login
请求,并设置status获取登录状态(成功or失败),详见login_page
函数, 在登录后实现files/holder
请求跳转,详见redirect_to_holder函数,并更新登录状态,代码如下:
def login_page(self): #登录 params = {"act":"submit","redirect_uri":"","area_code":"86","username":self.username,"password":self.password,"rememberme":False} self.respage = self.session.post(self.url,data=params,headers = self.headers) self.logger.info(self.url+" status_code: "+ str(self.respage.status_code)) self.generate_header("login") if str(self.respage.status_code) =="200" and self.status ==True: self.logger.info("++++++++oh my god, login succeed!++++++") else: self.status = False def redirect_to_holder(self): #跳转 if "data" in json.loads(self.respage.text): self.url = json.loads(self.respage.text)["data"] self.respage = self.session.get(self.url,headers = self.headers) self.logger.info(self.url+" status_code: "+ str(self.respage.status_code)) self.status = True else: self.status = False if str(self.respage.status_code) =="200" and self.status == True: self.logger.info("++++++++oh my god, redirect login succeed!++++++") else: self.status = False
(3)请求headers设置
def generate_header(self,action): if action=="login": self.headers["Referer"] = self.url self.headers["Accept"] ="text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" self.headers["Upgrade-Insecure-Requests"] = "1" self.tmp_cookie = requests.utils.dict_from_cookiejar(self.respage.cookies) if "_csc" in self.tmp_cookie and "JSESSID" in self.tmp_cookie and "S2" in self.tmp_cookie and "_cssu" in self.tmp_cookie: self.headers["Cookie"] ="_csc=%s;_csl=zh-cn;_oa=86,%s;JSESSID=%s;Hm_lvt_8f0191b1f1b207d4f6e0d42e771d6fde=%s;_ct=1;_isus=1;_cslt=1;S2=%s;_cssu=%s;_csste=%s;Hm_lvt_8f0191b1f1b207d4f6e0d42e771d6fde=%s;_cssrd=1"%(self.tmp_cookie["_csc"],self.username,self.tmp_cookie["JSESSID"],int(time.time()),self.tmp_cookie["S2"],self.tmp_cookie["_cssu"],int(time.time()),int(time.time())) else: self.status = False self.logger.warning(self.url+"登陆失败,headers设置失败") else: self.headers["Cache-Contro"] ='no-cache' self.headers["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8" self.headers["Accept"] = "text/plain, */*; q=0.01" self.headers["Referer"] = 'https://www.camscanner.com/files/holder' if "Upgrade-Insecure-Requests" in self.headers: self.headers.pop("Upgrade-Insecure-Requests") if "_csc" in self.tmp_cookie and "JSESSID" in self.tmp_cookie and "S2" in self.tmp_cookie and "_cssu" in self.tmp_cookie: self.headers["Cookie"] ="_csc=%s;_csl=zh-cn;_oa=86,%s;JSESSID=%s;Hm_lvt_8f0191b1f1b207d4f6e0d42e771d6fde=%s;_ct=1;_isus=1;_cslt=1;S2=%s;_cssu=%s;_csste=%s;Hm_lvt_8f0191b1f1b207d4f6e0d42e771d6fde=%s;_cssrd=1"%(self.tmp_cookie["_csc"],self.username,self.tmp_cookie["JSESSID"],int(time.time()),self.tmp_cookie["S2"],self.tmp_cookie["_cssu"],int(time.time()),int(time.time())) else: self.status = False self.logger.warning(self.url+"登陆失败,headers设置失败")
(4)获取文件列表
def get_file_list(self): self.url = "https://www.camscanner.com/doc/list" self.respage = self.session.post(self.url,headers = self.headers) #self.save_all() self.logger.info(self.url+" status_code: "+ str(self.respage.status_code)) self.file_list = eval(self.respage.text)["data"]["list"] self.logger.info("++++++++enheng, get file list succeed+++++++++++") (5)下载文件 def get_downloadfile_url_one(self,doc_id,title): self.generate_header("get download url") self.url = "https://www.camscanner.com/doc/downloadpdf" self.params = {"json_download":json.dumps({"docs":["%s.jdoc"%doc_id]})} times = 0 tmp = None while (times<5 and tmp == None): self.respage = self.session.post(self.url,data = self.params,headers = self.headers) times +=1 if "data" in self.respage.json(): tmp = self.respage.json()["data"] self.download_res["address"] = tmp self.download_res["filename"] = title + tmp[tmp.rfind("."):] self.logger.info("get %s address is : %s"%(title,tmp)) urllib.request.urlretrieve(self.download_res["address"],self.download_res["filename"]) self.logger.info("%s,下载完成"%self.download_res["filename"])
四、tkniter交互、pyinstaller封装exe
为方便程序可以脱离python环境使用,利用tkniter包设计简单的交互界面,主要设置登录界面(图4-1),若登录网页版全能版扫描王后成功后,跳转同步界面(图4-2),并在本地生成user_info文件,下次直接自动登录,跳过登录界面,点击开始同步(图4-3),将本地已经下载的文件跳过,直接下载未下载的文件,并更新本地文件列表,针对同步失败、切换账号、密码更改的需求,设置重新登录功能,将删除原有user_info文件,重新生成(图4-4),运行结果如图4-1至4-4:
4-1登录界面
4-2登录成功
4-3开始同步
4-4重新登录
将测过的代码进行封装,本文运行较为简单的命令:
pyinstaller -F -w downloadscan.py -i camscanner.ico
五、结语
下载本文全部代码(downloadscan.py)实现及封装程序(downloadscan.exe),请扫描下方二维码关注公众号后回复“抓包”获取
基于 requests 的全能扫描王爬虫实践相关推荐
- 制作一个类“全能扫描王”的简易扫描软件(opencv)
相信很多人手机里都装了个"扫描全能王"APP,平时可以用它来可以扫描一些证件.文本,确实很好用,第一次用的时候确实感觉功能很强大啊算法很牛逼啊.但是仔细一想,其实这些实现起来也是很 ...
- OpenCV制作一个类“全能扫描王”的简易扫描软件
转自:https://www.cnblogs.com/skyfsm/p/7324346.html 相信很多人手机里都装了个"扫描全能王"APP,平时可以用它来可以扫描一些证件.文本 ...
- 增强 扫描王 源码_OpenCV探索之路(二十二):制作一个类“全能扫描王”的简易扫描软件...
相信很多人手机里都装了个"扫描全能王"APP,平时可以用它来可以扫描一些证件.文本,确实很好用,第一次用的时候确实感觉功能很强大啊算法很牛逼啊.但是仔细一想,其实这些实现起来也是很 ...
- OpenCV实现“全能扫描王”的图像矫正功能
前言: 相信很多人手机里都装了个"扫描全能王"APP,平时可以用它来可以扫描一些证件.文本,确实很好用,第一次用的时候确实感觉功能很强大啊算法很牛逼啊.但是仔细一想,其实这些实现起 ...
- 【OpenCV】 ⚠️实战⚠️ 女子深夜久久不能入眠,300行写出全能扫描王! ☢️建议手收藏☢️
[OpenCV] ⚠️实战⚠️ 女子深夜久久不能入眠,300行写出全能扫描王! ☢️建议手收藏☢️ 概述 图像透视 获取透视矩阵 透视变换 预处理 其他函数 主函数 输出结果 最终转换结果 概述 今天 ...
- Python下基于requests及BeautifulSoup构建网络爬虫
功能说明 在Python下面可使用requests模块请求某个url获取响应的html文件,接着使用BeautifulSoup解析某个html. 案例 假设我要http://maoyan.com/bo ...
- Python 五行代码实现类似全能扫描王和office Lens的扫描彩色增强滤镜效果
安装第三方cv工具包:zisan pip install zisan zisan 开源的Github源码库:https://github.com/JintuZheng/zisan 项目代码持续更新维护 ...
- 智能扫描王 v1.0.0
类型:系统工具 版本:v1.0.0 大小:8.1M 更新:2019/3/4 语言:简体 等级: 平台:安卓, 4.0以上 下载地址: 智能扫描王 v1.0.0(1) 智能扫描王 v1.0.0(2) 智 ...
- Requests爬虫实践:豆瓣读书Top250数据
Requests爬虫实践:豆瓣读书Top250数据 本次的实践项目是爬取豆瓣读书Top250的书籍名称和网页地址 参考书籍:<Python网络爬虫从入门到实践> 书中爬的是电影数据,自己想 ...
最新文章
- ecshop 函数列表大全
- oracle数据库重建em,oracle 11g em重建报唯一约束错误解决方法
- jsp做看板_如何使用看板做敏捷开发
- java 管程通信_Java多线程07_线程通信之管程法与信号灯法
- 某大型银行深化系统技术方案之七:核心层之流程控制引擎
- 分布式存储引擎OceanBase,UpdateServer 实现机制——存储引擎
- 使用angrutils生成控制流图出错的解决过程
- 对主机或 Docker 镜像进行漏洞扫描
- 如何搭建一个好的测试环境
- pdf转word完全免费软件
- DeFi 2.0的LaaS协议,重振DeFi赛道发展的关键
- 国外计算机从什么开始学,从零开始学电脑知识 1(国外英语资料).doc
- matlab数组 xp,windowsxp系统将matlab数据导入excel的方法
- [arch Linux] 使用grub实现Linux和Windows双系统的引导
- Linux 登陆 分辨率,Linux系统登陆前后 分辨率不一致的问题
- Winter Camp I (下)
- 【摘录】使用BREW开发定位应用程序
- php 分页怎么实现的_php如何实现分页
- 排列熵算法--用于时间序列信号的复杂度检测
- Outlook 2007 发送邮件的发件人中文为问号的解决方法
热门文章
- 《R语言数据挖掘》读书笔记:三、分类
- 2021多益网络春季校园招聘游戏研发笔试题(回忆版)
- (C#)Windows Shell 外壳编程系列总结
- JS 异步编程的解决方案,以及回调地狱的解决方案
- SRS Audio Sandbox没有声音怎么办
- 牛客网练习,某公司2017秋招。叫车 2017年
- Sort_1000pics数据集利用CNN实现图像分类
- 《Python神经网络编程(Make Your Own Neural Network)》读书笔记
- 2021-2027全球与中国BFSI中的聊天机器人市场现状及未来发展趋势
- 解决vim-plug无法下载插件或者插件下载过慢的问题