怎么用有些网页没审查元素素下载网页里面的收费txt文本

&figure&&img src=&https://pic1.zhimg.com/v2-d_b.jpg& data-rawwidth=&1023& data-rawheight=&614& class=&origin_image zh-lightbox-thumb& width=&1023& data-original=&https://pic1.zhimg.com/v2-d_r.jpg&&&/figure&&p&分享一个爬虫,日抓取量级在千万左右,原文在:&a href=&http://link.zhihu.com/?target=http%3A//blog.csdn.net/bone_ace/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&新浪微博爬虫分享&/a&&/p&&h2&&b&代码请移步GitHub:&a href=&http://link.zhihu.com/?target=https%3A//github.com/LiuXingMing/SinaSpider/tree/master/Sina_spider1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SinaSpider&/a&&/b&&/h2&&h2&&b&爬虫功能:&/b&&/h2&&ul&&li&此项目和&a href=&http://link.zhihu.com/?target=http%3A//blog.csdn.net/bone_ace/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&QQ空间爬虫&/a&类似,主要爬取新浪微博用户的个人信息、微博信息、粉丝和关注(&a href=&http://link.zhihu.com/?target=http%3A//blog.csdn.net/bone_ace/article/details/Database& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&详细见此&/a&)。&/li&&li&代码获取新浪微博Cookie进行登录,可通过多账号登录来防止新浪的反扒(用来登录的账号可从淘宝购买,一块钱七个)。&/li&&li&项目爬的是新浪微博wap站,结构简单,速度应该会比较快,而且反扒没那么强,缺点是信息量会稍微缺少一些(可见&a href=&http://link.zhihu.com/?target=http%3A//blog.csdn.net/bone_ace/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&爬虫福利:如何爬wap站&/a&)。&/li&&li&爬虫抓取微博的速度可以达到 &b&1300万/天&/b& 以上,具体要视网络情况,我使用的是校园网(广工大学城校区),普通的家庭网络可能才一半的速度,甚至都不到。&/li&&/ul&&h2&&b&环境、架构:&/b&&/h2&&p&开发语言:Python2.7 &br&开发环境:64位Windows8系统,4G内存,i7-3612QM处理器。 &br&数据库:MongoDB 3.2.0 &br&(Python编辑器:Pycharm 5.0.4;MongoDB管理工具:MongoBooster 1.1.1)&/p&&ul&&li&主要使用 scrapy 爬虫框架。&/li&&li&下载中间件会从Cookie池和User-Agent池中随机抽取一个加入到spider中。&/li&&li&start_requests 中根据用户ID启动四个Request,同时对个人信息、微博、关注和粉丝进行爬取。&/li&&li&将新爬下来的关注和粉丝ID加入到待爬队列(先去重)。&/li&&/ul&&h2&&b&使用说明:&/b&&/h2&&p&启动前配置:&/p&&ul&&li&MongoDB安装好 能启动即可,不需要配置。&/li&&li&Python需要安装好scrapy(64位的Python尽量使用64位的依赖模块)&/li&&li&另外用到的python模块还有:pymongo、json、base64、requests。&/li&&li&将你用来登录的微博账号和密码加入到 cookies.py 文件中,里面已经有两个账号作为格式参考了。&/li&&li&另外一些scrapy的设置(如间隔时间、日志级别、Request线程数等)可自行在setting里面调。&/li&&/ul&&h2&&b&运行截图:&/b&&/h2&&figure&&img src=&https://pic1.zhimg.com/v2-c0a084be63ab0a633e746c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&995& data-rawheight=&707& class=&origin_image zh-lightbox-thumb& width=&995& data-original=&https://pic1.zhimg.com/v2-c0a084be63ab0a633e746c_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-bab67d38daa_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1236& data-rawheight=&716& class=&origin_image zh-lightbox-thumb& width=&1236& data-original=&https://pic3.zhimg.com/v2-bab67d38daa_r.jpg&&&/figure&&h2&&b&数据库说明:&/b&&/h2&&p&SinaSpider主要爬取新浪微博的个人信息、微博数据、关注和粉丝。 &br&数据库设置 Information、Tweets、Follows、Fans四张表,此处仅介绍前面两张表的字段。&/p&&blockquote&&b&Information 表:&/b& &br&_id:采用 “用户ID” 作为唯一标识。 &br&Birthday:出生日期。 &br&City:所在城市。 &br&Gender:性别。 &br&Marriage:婚姻状况。 &br&NickName:微博昵称。 &br&Num_Fans:粉丝数量。 &br&Num_Follows:关注数量。 &br&Num_Tweets:已发微博数量。 &br&Province:所在省份。 &br&Signature:个性签名。 &br&URL:微博的个人首页。&/blockquote&&p&&br&&/p&&blockquote&&b&Tweets 表:&/b& &br&_id:采用 “用户ID-微博ID” 的形式作为一条微博的唯一标识。 &br&Co_oridinates:发微博时的定位坐标(经纬度),调用地图API可直接查看具体方位,可识别到在哪一栋楼。 &br&Comment:微博被评论的数量。 &br&Content:微博的内容。 &br&ID:用户ID。 &br&Like:微博被点赞的数量。 &br&PubTime:微博发表时间。 &br&Tools:发微博的工具(手机类型或者平台) &br&Transfer:微博被转发的数量。&/blockquote&
分享一个爬虫,日抓取量级在千万左右,原文在:代码请移步GitHub:爬虫功能:此项目和类似,主要爬取新浪微博用户的个人信息、微博信息、粉丝和关注()。代码获取新浪微博Cookie进行登录,可通过多账号登录来…
&figure&&img src=&https://pic1.zhimg.com/v2-59a59b81aed78b89cab0c_b.jpg& data-rawwidth=&1114& data-rawheight=&586& class=&origin_image zh-lightbox-thumb& width=&1114& data-original=&https://pic1.zhimg.com/v2-59a59b81aed78b89cab0c_r.jpg&&&/figure&&p&爬虫初探系列一共4篇,耐心看完,我相信你就能基本了解爬虫是怎样工作的了,目录如下:&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&python爬虫初探(一):爬虫的基本结构&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&python爬虫初探(二):URL管理器和下载器&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&python爬虫初探(三):HTML解析器&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&折腾君:python爬虫初探(四):数据存储器&/a&&/p&&p&代码已上传至github,在python2.7下测试成功(请原谅我浓浓的乡村非主流代码风格)&a href=&http://link.zhihu.com/?target=https%3A//github.com/summerliehu/SimpleSpiderFramework& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&summerliehu/SimpleSpiderFramework&/a&&/p&&hr&&p&爬虫是个很奇妙的东西,这也是python的魅力所在——用非常简单的代码就能打造出一个功能强大的爬虫,去爬取你想收集的信息,将人类的双手从重复的工作中解放出来。但是,很多初学者往往在搞懂爬虫的基本原理上就下了很大的功夫,一段时间以来,我在学习python爬虫的过程中颇有心得体会,在这里稍加总结,希望能够给各位初学者一点启发。&/p&&p&爬虫,顾名思义,就是能够自主的对目标网页上的信息进行采集,并将采集到的数据进行存储的程序。对于爬虫的基本流程,已经有很多人对此进行了总结。然而,目前网上大部分对爬虫原理的讲解都过于复杂且晦涩难懂,难以为初学者所理解。所以我在这里根据自己的理解将爬虫爬取网络的过程画了下来,其基本的运行过程可以总结为下图(突然发现这个过程和生物学中的TCA cycle非常类似,事实上分子生物学正是我的专业!)。&/p&&p&爬虫对目标网页爬取的过程可以参考下面黑色文字部分:&/p&&ul&&li&首先访问初始url,获取其相应内容&/li&&li&对相应内容进行解析,提取感兴趣的信息和新的链接&/li&&li&将上一步提取到的数据存储,将获取到的链接去重并存储至仓库&/li&&li&从url仓库获得一条未爬取过的url,开始新的循环&/li&&/ul&&figure&&img src=&https://pic3.zhimg.com/v2-acd4ac453ac13b274eefa6_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&977& data-rawheight=&713& class=&origin_image zh-lightbox-thumb& width=&977& data-original=&https://pic3.zhimg.com/v2-acd4ac453ac13b274eefa6_r.jpg&&&/figure&&p&图片中由黑色文字组成的循环应该很好理解,那么具体到编程上来说,则必须将上面的流程进行抽象,我们可以编写几个元件,每个元件完成一项功能,上图中的蓝底白字就是对这一流程的抽象:&/p&&ul&&li&UrlManager:将存储和获取url以及url去重的几个步骤在url管理器中完成(当然也可以针对每一步分别编写相应的函数,但是这样更直观)。url管理器要有两个url仓库,一个存储未爬取的url,一个存储已爬取的url,除了仓库之外,还应该具有一些完成特定功能的函数,如存储url、url去重、从仓库中挑选并返回一个url等&/li&&li&HtmlDownloader:将下载网页内容的功能在HTML下载器中完成,下载器的功能较为单一,不多解释。但从整个爬虫的角度上来说,下载器是爬虫的核心,在实际操作的过程中,下载器要和目标网站的各种反爬虫手段斗智斗勇(各种表单、隐藏字段和假链接、验证码、IP限制等等),这也是最耗费大脑的步骤&/li&&li&HtmlParser:解析提取数据的功能在HTML解析器中完成,解析器内的函数应该分别具有返回数据和新url的功能&/li&&li&DAtaOutput:存储数据的功能由数据存储器完成&/li&&li&SpiderMan:主循环由爬虫调度器来完成,调度器为整个程序的入口,将其余四个元件有序执行&/li&&/ul&&p&OK,具体流程就是这样了,下面的图可能更加清楚一些:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-59a59b81aed78b89cab0c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1114& data-rawheight=&586& class=&origin_image zh-lightbox-thumb& width=&1114& data-original=&https://pic1.zhimg.com/v2-59a59b81aed78b89cab0c_r.jpg&&&/figure&&p&爬虫调度器将要完成整个循环,下面写出python下爬虫调度器的程序:&/p&&div class=&highlight&&&pre&&code class=&language-python3&&&span&&/span&&span class=&c1&&# coding: utf-8&/span&
&span class=&n&&new_urls&/span& &span class=&o&&=&/span& &span class=&nb&&set&/span&&span class=&p&&()&/span&
&span class=&n&&data&/span& &span class=&o&&=&/span& &span class=&p&&{}&/span&
&span class=&k&&class&/span& &span class=&nc&&SpiderMan&/span&&span class=&p&&(&/span&&span class=&nb&&object&/span&&span class=&p&&):&/span&
&span class=&k&&def&/span& &span class=&nf&&__init__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&c1&&#调度器内包含其它四个元件,在初始化调度器的时候也要建立四个元件对象的实例&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&manager&/span& &span class=&o&&=&/span& &span class=&n&&UrlManager&/span&&span class=&p&&()&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&downloader&/span& &span class=&o&&=&/span& &span class=&n&&HtmlDownloader&/span&&span class=&p&&()&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&parser&/span& &span class=&o&&=&/span& &span class=&n&&HtmlParser&/span&&span class=&p&&()&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&output&/span& &span class=&o&&=&/span& &span class=&n&&DataOutput&/span&&span class=&p&&()&/span&
&span class=&k&&def&/span& &span class=&nf&&spider&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&n&&origin_url&/span&&span class=&p&&):&/span&
&span class=&c1&&#添加初始url&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&n&&add_new_url&/span&&span class=&p&&(&/span&&span class=&n&&origin_url&/span&&span class=&p&&)&/span&
&span class=&c1&&#下面进入主循环,暂定爬取页面总数小于100&/span&
&span class=&n&&num&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&k&&while&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&n&&has_new_url&/span&&span class=&p&&()&/span& &span class=&ow&&and&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&n&&old_url_size&/span&&span class=&p&&()&/span&&span class=&o&&&&/span&&span class=&mi&&100&/span&&span class=&p&&):&/span&
&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&n&&num&/span& &span class=&o&&=&/span& &span class=&n&&num&/span& &span class=&o&&+&/span& &span class=&mi&&1&/span&
&span class=&nb&&print&/span& &span class=&s2&&&正在处理第&/span&&span class=&si&&{}&/span&&span class=&s2&&个链接&&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&n&&num&/span&&span class=&p&&)&/span&
&span class=&c1&&#从新url仓库中获取url&/span&
&span class=&n&&new_url&/span& &span class=&o&&=&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&n&&get_new_url&/span&&span class=&p&&()&/span&
&span class=&c1&&#调用html下载器下载页面&/span&
&span class=&n&&html&/span& &span class=&o&&=&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&downloader&/span&&span class=&o&&.&/span&&span class=&n&&download&/span&&span class=&p&&(&/span&&span class=&n&&new_url&/span&&span class=&p&&)&/span&
&span class=&c1&&#调用解析器解析页面,返回新的url和data&/span&
&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&n&&new_urls&/span&&span class=&p&&,&/span& &span class=&n&&data&/span& &span class=&o&&=&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&parser&/span&&span class=&o&&.&/span&&span class=&n&&parser&/span&&span class=&p&&(&/span&&span class=&n&&new_url&/span&&span class=&p&&,&/span& &span class=&n&&html&/span&&span class=&p&&)&/span&
&span class=&k&&except&/span& &span class=&ne&&Exception&/span&&span class=&p&&,&/span& &span class=&n&&e&/span&&span class=&p&&:&/span&
&span class=&nb&&print&/span& &span class=&n&&e&/span&
&span class=&k&&for&/span& &span class=&n&&url&/span& &span class=&ow&&in&/span& &span class=&n&&new_urls&/span&&span class=&p&&:&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&n&&add_new_url&/span&&span class=&p&&(&/span&&span class=&n&&url&/span&&span class=&p&&)&/span&
&span class=&c1&&#将已经爬取过的这个url添加至老url仓库中&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&n&&add_old_url&/span&&span class=&p&&(&/span&&span class=&n&&new_url&/span&&span class=&p&&)&/span&
&span class=&c1&&#将返回的数据存储至文件&/span&
&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&output&/span&&span class=&o&&.&/span&&span class=&n&&store_data&/span&&span class=&p&&(&/span&&span class=&n&&data&/span&&span class=&p&&)&/span&
&span class=&nb&&print&/span& &span class=&s2&&&store data succefully&&/span&
&span class=&k&&except&/span& &span class=&ne&&Exception&/span&&span class=&p&&,&/span& &span class=&n&&e&/span&&span class=&p&&:&/span&
&span class=&nb&&print&/span& &span class=&n&&e&/span&
&span class=&nb&&print&/span& &span class=&s2&&&第&/span&&span class=&si&&{}&/span&&span class=&s2&&个链接已经抓取完成&&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&n&&old_url_size&/span&&span class=&p&&())&/span&
&span class=&k&&except&/span& &span class=&ne&&Exception&/span&&span class=&p&&,&/span& &span class=&n&&e&/span&&span class=&p&&:&/span&
&span class=&nb&&print&/span& &span class=&n&&e&/span&
&span class=&c1&&#爬取循环结束的时候将存储的数据输出至文件&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&output&/span&&span class=&o&&.&/span&&span class=&n&&output_html&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&&br&&/p&&p&存储器、下载器、解析器和url管理器将在随后的文章中给出分析。&/p&&p&&br&&/p&&p&————————————————&/p&&p&本文的写作过程中参考了以下资料:&/p&&p&《Python爬虫开发与项目实战》,范传辉 编著&/p&&p&《Python网络数据采集》[美] 米切尔(Ryan Mitchell) 著&/p&&p&Python爬虫学习系列教程(来自崔庆才的博客)&/p&&p&&/p&&p&&/p&
爬虫初探系列一共4篇,耐心看完,我相信你就能基本了解爬虫是怎样工作的了,目录如下:代码已上传…
&figure&&img src=&https://pic3.zhimg.com/v2-7ef199dec1_b.jpg& data-rawwidth=&2560& data-rawheight=&1600& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&https://pic3.zhimg.com/v2-7ef199dec1_r.jpg&&&/figure&&p&之前写的爬取拉钩网,在使用Ajax接口时,如果我们post的速度过快,会返回请求过于频繁的提示,并且会提示我们的IP地址。在爬虫的过程中暂时封IP太常见了,所以就想做个IP代理池,放在一直没启用的腾讯云服务器上,这里给出一个Web调用接口:&a href=&https://link.zhihu.com/?target=http%3A//111.230.144.236%3A5010/get_all/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&服务器接口(配置不高,注意速度)&/a&&/p&&h2&获取结果&/h2&&figure&&img src=&https://pic4.zhimg.com/v2-b8c9e3ad49ccf5e1e4c4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&650& data-rawheight=&315& class=&origin_image zh-lightbox-thumb& width=&650& data-original=&https://pic4.zhimg.com/v2-b8c9e3ad49ccf5e1e4c4_r.jpg&&&/figure&&p&get_all参数获取全部IP&/p&&figure&&img src=&https://pic3.zhimg.com/v2-12c0cf2a68c953caed2b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&576& data-rawheight=&985& class=&origin_image zh-lightbox-thumb& width=&576& data-original=&https://pic3.zhimg.com/v2-12c0cf2a68c953caed2b_r.jpg&&&/figure&&p&&br&&/p&&p&看完效果开始搭建,项目来源于github---&a href=&https://link.zhihu.com/?target=https%3A//github.com/jhao104/proxy_pool& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&jhao104/proxy_pool&/a&&/p&&p&这个项目十分简单,源码也不多&/p&&p&项目兼容Python2.7和Python3.x,win10和Ubuntu测试通过&/p&&h2&下载安装&/h2&&ul&&li&下载源码&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&git clone :jhao104/proxy_pool.git
或者直接到https://github.com/jhao104/proxy_pool 下载zip文件,解压出来
&/code&&/pre&&/div&&h2&安装依赖&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&pip install -r requirements.txt # 这是github作者给出的安装方式
# 如果安装有问题,可以找到txt文件自己手动安装所需库
&/code&&/pre&&/div&&h2&下载redis数据库&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&windows下载地址:https://github.com/MicrosoftArchive/redis/releases
启动redis:运行redis-server.exe(不要关闭)
查看状态:redis-cli.exe
Linux安装:sudo apt-get install redis-server
启动redis:运行redis-server
查看状态:redis-cli
&/code&&/pre&&/div&&p&附上redis的相关资料:&a href=&https://link.zhihu.com/?target=http%3A//www.runoob.com/redis/redis-commands.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Redis 命令 | 菜鸟教程&/a&&/p&&h2&配置Config.ini:&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# Config.ini 为项目配置文件
type = SSDB
# 如果使用SSDB或redis数据库,均配置为SSDB
host = localhost
# db host, 不行就用127.0.0.1
port = 6379
# db port, redis默认是6379
name = proxy
# 默认配置
# 配置 ProxyGetter
freeProxyFirst
# 这里是启动的抓取函数,可在ProxyGetter/getFreeProxy.py 扩展
freeProxySecond = 1
# 配置 HOST (api服务)
ip = 127.0.0.1
# 监听ip, 若要开启外网访问改为0.0.0.0
port = 5010
# 监听端口
# 上面配置启动后,代理api地址为 http://127.0.0.1:5010
&/code&&/pre&&/div&&p&&br&&/p&&h2&启动&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# 如果你的依赖已经安全完成并且具备运行条件,可以直接在Run目录下运行main.py
# 到Run目录下:
&&&python main.py
# 如果运行成功你应该看到有4个main.py进程
# 你也可以分别运行他们,
# 依次到Api下启动ProxyApi.py,Schedule下启动ProxyRefreshSchedule.py和ProxyValidSchedule.py即可.
&/code&&/pre&&/div&&p&&br&&/p&&h2&使用&/h2&&p&  启动过几分钟后就能看到抓取到的代理IP,你可以直接到数据库中查看,推荐一个&a href=&https://link.zhihu.com/?target=https%3A//github.com/jhao104/SSDBAdmin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SSDB可视化工具&/a& &/p&&p&  也可以通过api访问&a href=&https://link.zhihu.com/?target=http%3A//127.0.0.1%3A5010/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&http://127.0.0.1:5010&/a& 查看。&/p&&p&附上Api:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-ec47e1c03afcc7284174_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&521& data-rawheight=&280& class=&origin_image zh-lightbox-thumb& width=&521& data-original=&https://pic1.zhimg.com/v2-ec47e1c03afcc7284174_r.jpg&&&/figure&&p&这是我跑了一晚上的结果。每隔一段时间会更新IP数量,拿到的IP很多。还可以加入自己的代理IP接口:&a href=&https://link.zhihu.com/?target=https%3A//github.com/jhao104/proxy_pool%23%25E6%%25E5%25B1%%25BB%25A3%25E7%& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&扩展代理&/a&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-fb606fc033b153aee8f93f_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&550& data-rawheight=&249& class=&origin_image zh-lightbox-thumb& width=&550& data-original=&https://pic4.zhimg.com/v2-fb606fc033b153aee8f93f_r.jpg&&&/figure&&h2&demo&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&import requests
def get_proxy():
#可以换成我的Api
return requests.get(&http://127.0.0.1:5010/get/&).text
def delete_proxy(proxy):
requests.get(&http://127.0.0.1:5010/delete/?proxy={}&.format(proxy))
# your spider code
def getHtml():
retry_count = 5
proxy = get_proxy()
while retry_count & 0:
html = requests.get('https://www.baidu.com',
proxies={&http&: &http://{}&.format(proxy),&https&: &https://{}&.format(proxy)})
# 使用代理访问
return html
except Exception:
retry_count -= 1
# 出错5次, 删除代理池中代理
delete_proxy(proxy)
return None
&/code&&/pre&&/div&&p&&br&&/p&&h2&总结&/h2&&p&免费的IP代理池搭建很简单,但是质量也不高,简单测试了拉钩网虽然不会返回请求频繁的问题,但是免费代理IP的可用性不高,估计购买付费IP代理应该更稳定一些。&/p&
之前写的爬取拉钩网,在使用Ajax接口时,如果我们post的速度过快,会返回请求过于频繁的提示,并且会提示我们的IP地址。在爬虫的过程中暂时封IP太常见了,所以就想做个IP代理池,放在一直没启用的腾讯云服务器上,这里给出一个Web调用接口:
&figure&&img src=&https://pic1.zhimg.com/v2-4ab6e9fba1d09eb871eb7_b.jpg& data-rawwidth=&550& data-rawheight=&309& class=&origin_image zh-lightbox-thumb& width=&550& data-original=&https://pic1.zhimg.com/v2-4ab6e9fba1d09eb871eb7_r.jpg&&&/figure&&p&今天打算写最后一篇的反爬与反反爬的文章了,毕竟奇技淫巧很多,但是万变不离其宗,熟练掌握JS/HTML/CSS,了解HTTP协议,这是内功。熟练使用chrome,神箭手开发框架,这是称手的兵器。剩下的也就是唯手熟尔。&/p&&p&后面打算开一个番外系列,不少人私信问我关于cnn识别验证码的问题,所以打算开一个系列跟大家一起看看咱们用机器学习能解决多少验证码识别的问题。感兴趣的朋友欢迎关注我或者专栏:&/p&&p&我:&a href=&https://www.zhihu.com/people/wu-tong-v2& class=&internal&&吴桐-神箭手CEO&/a&&/p&&p&专栏:&a href=&https://zhuanlan.zhihu.com/data-factory& class=&internal&&数据黑板-知乎专栏&/a&&/p&&p&好了,废话不多说,先上之前的文章列表:&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&爬虫被封IP了怎么办-反爬与反反爬的奇技淫巧&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&爬虫中的验证码识别-反爬与反反爬的奇技淫巧&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&爬虫中Cookie的伪造(非登录)-反爬与反反爬的奇技淫巧&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&爬虫与诡异的字体-反爬与反反爬的奇技淫巧&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&爬虫与汽车之家的Css:Content-反爬与反反爬的奇技淫巧&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&爬虫与CloudFlare邮箱加密(cfemail)-反爬与反反爬的奇技淫巧&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&那些年携程工程师在代码里下的毒-反爬与反反爬的奇技淫巧&/a&&/p&&p&一眼望去已经有不少文章了,不过也应该只覆盖了所有套路的一部分吧,今天既然是压轴,我们就来聊一个难的,诡异的,不一样的,眼前一亮的。常规的单独套路显然就很难符合标准,今天咱们要聊的是一个超级组合拳直接让人怀疑人生的反爬套路--商标局(&a href=&https://link.zhihu.com/?target=http%3A//wsjs.saic.gov.cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&商标检索平台&/a&)。&/p&&p&首先呢,我们的文章只是技术探索的目的。商标局的网站反爬据说是一家专业安全企业的产品-瑞数 ,我们不会在这篇文章中教大家完整去破解这套系统。我们一起来通过研究这套系统,看看我们有什么可以借鉴的地方,这套策略到底有什么牛逼的地方。同时提高我们的反爬与反反爬的能力,当然最重要的是提高JS水平。&/p&&p&好了,既然是组合拳,咱们就一个一个拳头来:&/p&&p&&b&第一拳:防调试&/b&&/p&&p&咱们依照套路,直接打开网站,右击打开调试面板。Boom!&/p&&figure&&img src=&https://pic4.zhimg.com/v2-a03d103f1fbdb6952beda6ae6e7304a7_b.jpg& data-rawwidth=&1345& data-rawheight=&592& class=&origin_image zh-lightbox-thumb& width=&1345& data-original=&https://pic4.zhimg.com/v2-a03d103f1fbdb6952beda6ae6e7304a7_r.jpg&&&/figure&&p&直接断点,咱们还啥都没做呢,点击继续,Boom!又断点。这还没上战场,就已经被打残了。&/p&&p&首先不得不说专业的就是专业的,这招简直是不战而屈人之兵。很多人走到这,就已经决定去用无头浏览器了(当然无头浏览器的坑也很多,更致命的是灵活性太差)&/p&&p&这里有一个不算完美的解决方案,就是我安利了无数篇文章的chrome snippets,这里可以明显看到,这个手法是内嵌了一个setinterval的函数,每一个间隔时间,就调用一次debugger让浏览器断点,我们只需要清楚掉这个interval即可,大家可以复制一下下面的代码在console中执行,或者直接保存成snippet每次断点后执行再点继续即可。&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&k&&for&/span& &span class=&p&&(&/span&&span class=&kd&&var&/span& &span class=&nx&&i&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span& &span class=&nx&&i&/span& &span class=&o&&&&/span& &span class=&mi&&99999&/span&&span class=&p&&;&/span& &span class=&nx&&i&/span&&span class=&o&&++&/span&&span class=&p&&)&/span&
&span class=&nb&&window&/span&&span class=&p&&.&/span&&span class=&nx&&clearInterval&/span&&span class=&p&&(&/span&&span class=&nx&&i&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&p&&b&第二拳:JS验证后跳转&/b&&/p&&p&闪过第一拳,第二拳迅速袭来,网页本身并不是直接打开的,而是经过了一次JS跳转,跳转到了这样一个网址上:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&http://wsjs.saic.gov.cn/txnT01.do?y7bRbP=KaltkM10zh10zh10triDHWegi3_iGKEpBPgY7GGba.A
&/code&&/pre&&/div&&p&JS跳转是很多网站验证真实浏览器的方式(比如还有搜狗搜索),当然商标网的这个JS跳转那也真是成精了。由于直接在Chrome中即使勾上preserved log也拿不到具体页面,我们通过postman来提交一个请求看看真实的返回数据:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-caf3d467c28ee08_b.jpg& data-rawwidth=&1344& data-rawheight=&882& class=&origin_image zh-lightbox-thumb& width=&1344& data-original=&https://pic3.zhimg.com/v2-caf3d467c28ee08_r.jpg&&&/figure&&p&这代码看着也真实让人精神抖擞啊,关于这类JS的调试,我已经在上篇文章中,有着相对详细介绍,如果还是没有掌握其中奥义的朋友们,可以自行学习,我就不详细讲了。这里特别注意几个细节:&/p&&p&1.这里不仅仅纯粹JS需要执行,还有一个重要的meta标签和一个外部引用的JS文件都需要模拟到Snippets里去,而且必须要对应上,否则函数名就会错乱。&/p&&p&2.实际代码运行过程中,还有两套JS的eval执行,谨记用console.log替换eval的套路。&/p&&p&3.代码中有部分代码调用了eval.call的方法,注意此方法会将context换成全局的context执行,模拟的时候务必弄清环境以免变量错乱。&/p&&p&4.模拟真实浏览器环境的过程中,类似携程的new Image()套路,这套反爬代码中也下了不少毒。比如navigator的hasOwnProperty,大家在模拟环境变量时一定做到真实模拟,比如内置变量尽量使用定义prototype后new的形式,而不要直接定义一个变量:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&nx&&Navigator&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&&span class=&s2&&&appVersion&&/span&&span class=&o&&:&/span&&span class=&s2&&&5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0. Safari/537.36&&/span&&span class=&p&&,&/span&
&span class=&s2&&&appCodeName&&/span&&span class=&o&&:&/span&&span class=&s2&&&Mozilla&&/span&&span class=&p&&,&/span&
&span class=&s2&&&appName&&/span&&span class=&o&&:&/span&&span class=&s2&&&Netscape&&/span&&span class=&p&&,&/span&
&span class=&s2&&&language&&/span&&span class=&o&&:&/span&&span class=&s2&&&zh-CN&&/span&&span class=&p&&,&/span&
&span class=&s2&&&platform&&/span&&span class=&o&&:&/span&&span class=&s2&&&Win32&&/span&&span class=&p&&,&/span&
&span class=&s2&&&productSub&&/span&&span class=&o&&:&/span&&span class=&s2&&&&&/span&&span class=&p&&,&/span&
&span class=&s2&&&product&&/span&&span class=&o&&:&/span&&span class=&s2&&&Gecko&&/span&&span class=&p&&,&/span&
&span class=&s2&&&mimeTypes&&/span&&span class=&o&&:&/span&&span class=&p&&[&/span&
&span class=&p&&{&/span&&span class=&s2&&&type&&/span&&span class=&o&&:&/span&&span class=&s2&&&application/pdf&&/span&&span class=&p&&,&/span&&span class=&s2&&&description&&/span&&span class=&o&&:&/span&&span class=&s2&&&&&/span&&span class=&p&&,&/span&&span class=&s2&&&enabledPlugin&&/span&&span class=&o&&:&/span&&span class=&p&&{&/span&&span class=&s2&&&name&&/span&&span class=&o&&:&/span&&span class=&s2&&&PDF Viewer&&/span&&span class=&p&&}},&/span&
&span class=&p&&{&/span&&span class=&s2&&&type&&/span&&span class=&o&&:&/span&&span class=&s2&&&application/x-shockwave-flash&&/span&&span class=&p&&,&/span&&span class=&nx&&suffixes&/span&&span class=&o&&:&/span&&span class=&s2&&&swf&&/span&&span class=&p&&,&/span&
&span class=&s2&&&description&&/span&&span class=&o&&:&/span&&span class=&s2&&&Shockwave Flash&&/span&&span class=&p&&,&/span&&span class=&s2&&&enabledPlugin&&/span&&span class=&o&&:&/span&&span class=&p&&{&/span&&span class=&s2&&&name&&/span&&span class=&o&&:&/span&&span class=&s2&&&Shockwave Flash&&/span&&span class=&p&&,&/span&&span class=&s2&&&description&&/span&&span class=&o&&:&/span&&span class=&s2&&&Shockwave Flash 26.0 r0&&/span&&span class=&p&&}}&/span&
&span class=&p&&],&/span&
&span class=&s2&&&userAgent&&/span&&span class=&o&&:&/span&&span class=&nx&&site&/span&&span class=&p&&.&/span&&span class=&nx&&getUserAgent&/span&&span class=&p&&(),&/span&
&span class=&s2&&&languages&&/span&&span class=&o&&:&/span& &span class=&p&&[&/span&&span class=&s2&&&zh-CN&&/span&&span class=&p&&,&/span& &span class=&s2&&&zh&&/span&&span class=&p&&],&/span&
&span class=&s2&&&plugins&&/span&&span class=&o&&:&/span&&span class=&p&&[&/span&
&span class=&p&&{&/span&&span class=&s2&&&name&&/span&&span class=&o&&:&/span&&span class=&s2&&&Shockwave Flash&&/span&&span class=&p&&,&/span&&span class=&s2&&&description&&/span&&span class=&o&&:&/span&&span class=&s2&&&Shockwave Flash 26.0 r0&&/span&&span class=&p&&,&/span&&span class=&nx&&length&/span&&span class=&o&&:&/span&&span class=&mi&&2&/span&&span class=&p&&,&/span&&span class=&nx&&filename&/span&&span class=&o&&:&/span&&span class=&s2&&&pepflashplayer64_26_0_0_151.dll&&/span&&span class=&p&&}&/span&
&span class=&p&&]&/span&
&span class=&p&&};&/span&
&span class=&nx&&navigator&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Navigator&/span&&span class=&p&&();&/span&
&/code&&/pre&&/div&&p&5.代码中有大量dom操作,但是我们模拟环境是不可能模拟所有dom操作的(真全部模拟出来就是个无头浏览器了,这工作量不可想象)所以建议先写一个空dom函数的,看看具体的调用形式,比如document.getElementById之类,打印一下看看如何调用,然后在模拟具体场景下的使用,比如获取meta标签的content。&/p&&p&6.调试过程中会发现正常运行可以,但是一旦调试则乱码,此处又是工程师下的剧毒,通过比对执行时间差来判断是否是有人在debug,此处解决方案可执行如下代码替换Date的默认执行来骗过JS:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&nb&&Date&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&_getTime&/span& &span class=&o&&=&/span& &span class=&nb&&Date&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&getTime&/span&&span class=&p&&;&/span&
&span class=&nb&&Date&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&getTime&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span&&span class=&p&&(){&/span&
&span class=&k&&if&/span&&span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&nb&&Date&/span&&span class=&p&&.&/span&&span class=&nx&&_lastTime&/span&&span class=&p&&){&/span&
&span class=&kd&&var&/span& &span class=&nx&&time&/span& &span class=&o&&=&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&_getTime&/span&&span class=&p&&();&/span&
&span class=&nb&&Date&/span&&span class=&p&&.&/span&&span class=&nx&&_lastTime&/span& &span class=&o&&=&/span& &span class=&nx&&time&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&nb&&Date&/span&&span class=&p&&.&/span&&span class=&nx&&_lastTime&/span& &span class=&o&&=&/span& &span class=&nb&&Date&/span&&span class=&p&&.&/span&&span class=&nx&&_lastTime&/span&&span class=&o&&+&/span&&span class=&mi&&100&/span&&span class=&p&&;&/span&
&span class=&k&&return&/span& &span class=&nb&&Date&/span&&span class=&p&&.&/span&&span class=&nx&&_lastTime&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&7.耐心!耐心!耐心!由于此处套路之深让携程工程师都看不到底,所以调试的耐心非常重要。&/p&&p&&b&第三拳:Cookie的定时刷新&/b&&/p&&p&其实如果我没猜错,第二拳打完,估计地上应该已经全是尸体了,不过记得当年游戏里的一句话:十人九不回,强者尸上行(又暴露年龄了)。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-8e5ead2ad4_b.jpg& data-rawwidth=&1920& data-rawheight=&800& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic1.zhimg.com/v2-8e5ead2ad4_r.jpg&&&/figure&&p&&br&&/p&&p&咱们继续前行,看看这第三拳:Cookie定时刷新。此处套路已经要突破天际了,宇宙边缘才是这套路的终点。此处JS通过将点击行为,停留时间等等以加密形式存入Cookie中,并定时刷新,几乎做到让想要模拟的人走投无路,不过值得庆幸的是如果顺利挺过第二拳,这第三拳只需要加上一个对浏览器事件机制的模拟即可顺利过关。&/p&&p&&b&第四拳:浏览器内置函数Hook&/b&&/p&&p&估计到了第四拳,不少内功差的朋友已经不知道我在说什么了。如果还能看懂的话,咱们继续:&/p&&p&这套反爬最让我们叹为观止的,就是这第四拳,真的是非常的优雅。又把安全做到了几乎是前段的极致。系统通过对XMLHttpRequest的Hook,将所有的Ajax请求都添加上了get参数,就算普通调试,甚至都完全看不出来get参数是再什么地方加的。不过解决方案当然也很简单,就是对XMLHttpRequest先做一次Hook,在执行代码。&/p&&p&&b&第五拳:表单提交代替链接&/b&&/p&&p&这个套路虽然不深,但确实也给调试带来了深深的影响,然而还好走到这的朋友估计已经对这套代码烂熟于心,只需要跳过表单提交,通过其他方案直接获取Url和get参数,同时通过Hook函数document.write就可以完美模拟出表单提交的效果。&/p&&p&&br&&/p&&p&话说后面两拳我就不展开了说了,躲过这几拳之后,剩下的就非常简单了,最后的页面连一个ajax都没有,直接xpath就可以全部解析出来。如果大家想把JS提升5678个档次,可以来尝试下商标局网的爬虫。这个爬虫写出来之后,你会发现携程爬虫真的也只算得上小学水平吧。&/p&&p&&br&&/p&&p&--------------------------------------------------最后说两句----------------------------------------------------------&/p&&p&咱们反爬和反反爬系列就此告一段落了,还是开头说了,套路很多,一一列举没啥意思,大家掌握思想精髓,做到举一反三,才能真正通往大神之路。&/p&&p&欢迎大家继续关注我和我的专栏,下面开启一个新系列《验证码终结者》,跟大家一起通过新武器-人工智能来会会这个爬虫的老对手(参看&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&爬虫中的验证码识别-反爬与反反爬的奇技淫巧&/a&)。&/p&&p&&br&&/p&&p&更多回答关注:&a href=&https://www.zhihu.com/people/wu-tong-v2& class=&internal&&吴桐-神箭手CEO&/a&&/p&&p&更多文章关注:&a href=&https://zhuanlan.zhihu.com/data-factory& class=&internal&&数据黑板-知乎专栏&/a&&/p&&p&&/p&&p&&/p&&p&&/p&
今天打算写最后一篇的反爬与反反爬的文章了,毕竟奇技淫巧很多,但是万变不离其宗,熟练掌握JS/HTML/CSS,了解HTTP协议,这是内功。熟练使用chrome,神箭手开发框架,这是称手的兵器。剩下的也就是唯手熟尔。后面打算开一个番外系列,不少人私信问我关于cnn…
&figure&&img src=&https://pic1.zhimg.com/v2-d7fee9d92bbc919fa73ae38df65c08bc_b.jpg& data-rawwidth=&640& data-rawheight=&316& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic1.zhimg.com/v2-d7fee9d92bbc919fa73ae38df65c08bc_r.jpg&&&/figure&&p&学任何一门技术,都应该带着目标去学习,目标就像一座灯塔,指引你前进,很多人学着学着就学放弃了,很大部分原因是没有明确目标,所以,在你准备学爬虫前,先问问自己为什么要学习爬虫。有些人是为了一份工作,有些人是为了好玩,也有些人是为了实现某个黑科技功能。不过 肯定的是,学会了爬虫,能给你的工作提供很多便利。&/p&&p&作为零基础小白,大体上可分为三个阶段去实现,第一阶段是入门,掌握必备基础知识,比如Python基础、网络请求的基本原理等,第二阶段是模仿,跟着别人的爬虫代码学,弄懂每一行代码,熟悉主流的爬虫工具,第三阶段是自己动手,到了这个阶段你开始有自己的解题思路了,可以独立设计爬虫系统。&/p&&p&爬虫涉及的技术包括但不限于熟练一门编程语言(这里以 Python 为例) HTML 知识、HTTP 协议的基本知识、正则表达式、数据库知识,常用抓包工具的使用、爬虫框架的使用、涉及到大规模爬虫,还需要了解分布式的概念、消息队列、常用的数据结构和算法、缓存,甚至还包括机器学习的应用,大规模的系统背后都是靠很多技术来支撑的。数据分析、挖掘、甚至是机器学习都离不开数据,而数据很多时候需要通过爬虫来获取,因此,作为一门专业爬虫工程师都是有很大的前途的。&/p&&p&那么是不是一定要把上面的知识全学完了才可以开始写爬虫吗?当然不是,学习是一辈子的事,只要你会写 Python 代码了,就直接上手爬虫,好比学车,只要能开动了就上路吧,写代码可比开车安全多了。&/p&&p&用 Python 写爬虫,首先需要会 Python,把基础语法搞懂,知道怎么使用函数、类、list、dict 中的常用方法就算基本入门。接着你需要了解 HTML,HTML 就是一个文档树结构,网上有个 HTML 30分钟入门教程 &a href=&https://link.zhihu.com/?target=https%3A//deerchao.net/tutorials/html/html.htm& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&deerchao.net/tutorials/&/span&&span class=&invisible&&html/html.htm&/span&&span class=&ellipsis&&&/span&&/a& 够用了。然后是关于 HTTP 的知识,爬虫基本原理就是通过网络请求从远程服务器下载数据的过程,而这个网络请求背后的技术就是基于 HTTP 协议。作为入门爬虫来说,你需要了解 HTTP协议的基本原理,虽然 HTTP 规范用一本书都写不完,但深入的内容可以放以后慢慢去看,理论与实践相结合。&/p&&p&网络请求框架都是对 HTTP 协议的实现,比如著名的网络请求库 Requests 就是一个模拟浏览器发送 HTTP 请求的网络库。了解 HTTP 协议之后,你就可以专门有针对性的学习和网络相关的模块了,比如 Python 自带有 urllib、urllib2(Python3中的urllib),httplib,Cookie等内容,当然你可以直接跳过这些,直接学习 Requests 怎么用,前提是你熟悉了 HTTP协议的基本内容,数据爬下来,大部分情况是 HTML 文本,也有少数是基于 XML 格式或者 Json 格式的数据,要想正确处理这些数据,你要熟悉每种数据类型的解决方案,比如 JSON 数据可以直接使用 Python自带的模块 json,对于 HTML 数据,可以使用 BeautifulSoup、lxml 等库去处理,对于 xml 数据,除了可以使用 untangle、xmltodict 等第三方库。&/p&&p&爬虫工具里面,学会使用 Chrome 或者 FireFox 浏览器去审查元素,跟踪请求信息等等,现在大部分网站有配有APP和手机浏览器访问的地址,优先使用这些接口,相对更容易。还有 Fiddler 等代理工具的使用。&/p&&p&入门爬虫,学习正则表达式并不是必须的,你可以在你真正需要的时候再去学,比如你把数据爬取回来后,需要对数据进行清洗,当你发现使用常规的字符串操作方法根本没法处理时,这时你可以尝试了解一下正则表达式,往往它能起到事半功倍的效果。Python 的 re 模块可用来处理正则表达式。这里也推荐一个教程:Python正则表达式指南 &a href=&https://link.zhihu.com/?target=https%3A//www.cnblogs.com/huxi/archive//1771073.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&cnblogs.com/huxi/archiv&/span&&span class=&invisible&&e//1771073.html&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&数据清洗完最终要进行持久化存储,你可以用文件存储,比如CSV文件,也可以用数据库存储,简单的用 sqlite,专业点用 MySQL,或者是分布式的文档数据库 MongoDB,这些数据库对Python都非常友好,有现成的库支持,你要做的就是熟悉这些 API 怎么使用。&/p&&p&从数据的抓取到清洗再到存储的基本流程都走完了,也算是基本入门了,接下来就是考验内功的时候了,很多网站都设有反爬虫策略,他们想方设法阻止你用非正常手段获取数据,比如会有各种奇奇怪怪的验证码限制你的请求操作、对请求速度做限制,对IP做限制、甚至对数据进行加密操作,总之,就是为了提高获取数据的成本。这时你需要掌握的知识就要更多了,你需要深入理解 HTTP 协议,你需要理解常见的加解密算法,你要理解 HTTP 中的 cookie,HTTP 代理,HTTP中的各种HEADER。爬虫与反爬虫就是相爱相杀的一对,道高一次魔高一丈。如何应对反爬虫没有既定的统一的解决方案,靠的是你的经验以及你所掌握的知识体系。这不是仅凭21天入门教程就能达到的高度。&/p&&p&进行大规模爬虫,通常都是从一个URL开始爬,然后把页面中解析的URL链接加入待爬的URL集合中,我们需要用到队列或者优先队列来区别对待有些网站优先爬,有些网站后面爬。每爬去一个页面,是使用深度优先还是广度优先算法爬取下一个链接。每次发起网络请求的时候,会涉及到一个DNS的解析过程(将网址转换成IP)为了避免重复地 DNS 解析,我们需要把解析好的 IP 缓存下来。URL那么多,如何判断哪些网址已经爬过,哪些没有爬过,简单点就是是使用字典结构来存储已经爬过的的URL,但是如果碰过海量的URL时,字典占用的内存空间非常大,此时你需要考虑使用 Bloom Filter(布隆过滤器),用一个线程逐个地爬取数据,效率低得可怜,如果提高爬虫效率,是使用多线程,多进程还是协程,还是分布式操作。&/p&&p&欢迎关注公众号:Python之禅&/p&
学任何一门技术,都应该带着目标去学习,目标就像一座灯塔,指引你前进,很多人学着学着就学放弃了,很大部分原因是没有明确目标,所以,在你准备学爬虫前,先问问自己为什么要学习爬虫。有些人是为了一份工作,有些人是为了好玩,也有些人是为了实现某个黑…
&figure&&img src=&https://pic4.zhimg.com/v2-18f0e8f9aaf1ea1d2712933e_b.jpg& data-rawwidth=&2192& data-rawheight=&2927& class=&origin_image zh-lightbox-thumb& width=&2192& data-original=&https://pic4.zhimg.com/v2-18f0e8f9aaf1ea1d2712933e_r.jpg&&&/figure&&p&爬虫在大数据时代占据了重要的位置,在网上有大量的公开数据可以轻松获取。&/p&&p&爬虫入门其实非常简单,就算&b&你是编程小白,也可以轻松爬下一些网站&/b&。下面就以&b&爬取笔者的个人博客网站(&a href=&https://link.zhihu.com/?target=http%3A//www.santostang.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&大数据分析@唐松&/a&)&/b&为例,教大家学会一个简单的爬虫。。一方面,由于这个网站的设计和框架不会更改,因此本书的网络爬虫代码可以一直使用; 另一方面,由于这个网站由笔者拥有,因此避免了一些法律上的风险。&/p&&p&如果你有已经安装了python3,pip,可以跳过下面对python,pip安装的介绍。&/p&&p&&br&&/p&&h2&1. 安装python3, pip, beautifulsoup&/h2&&p&第一步:Python3安装,请自行百度 Anaconda。这里推荐使用 Anaconda 的 Python 科学计算环境。只需像普通软件一样安装好 Anaconda,就可以把 Python 的环境变量、解释器、开发环境等安装在计算机中。&/p&&p&第二步:安装pip,pip是按照python各种包的工具,有了它安装python的各种包都很方便。如果你安装了 Anaconda,那么恭喜你,它已经自带了 pip 不用单独安装了。&/p&&p&如果不使用 Anaconda 安装 Python,需要单独装 pip,可以借鉴这篇文章:&a href=&https://link.zhihu.com/?target=http%3A//www.tuicool.com/articles/eiM3Er3/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&tuicool.com/articles/ei&/span&&span class=&invisible&&M3Er3/&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&第三步:有了pip,就可以安装beautifulsoup了。这个包可以很好地从网页代码中提取想要的数据。安装方法: 在 terminal (MacOS) 或是 cmd (Windows)中键入&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&pip install bs4
&/code&&/pre&&/div&&p&第四步:选一个python编译器来跑程序。为了代码的调试方便,可以直接用 Anaconda 中的 jupyter。使用方法:在 terminal (MacOS) 或是 cmd (Windows)中键入&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&jupyter notebook
&/code&&/pre&&/div&&p&&br&&/p&&h2&2. 第一步:获取页面&/h2&&div class=&highlight&&&pre&&code class=&language-python3&&&span&&/span&&span class=&ch&&#!/usr/bin/python&/span&
&span class=&c1&&# coding: utf-8&/span&
&span class=&kn&&import&/span& &span class=&nn&&requests&/span&
&span class=&n&&link&/span& &span class=&o&&=&/span& &span class=&s2&&&http://www.santostang.com/&&/span&
&span class=&n&&headers&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&&span class=&s1&&'User-Agent'&/span& &span class=&p&&:&/span& &span class=&s1&&'Mozilla/5.0 (W U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/ Firefox/3.5.6'&/span&&span class=&p&&}&/span&
&span class=&n&&r&/span& &span class=&o&&=&/span& &span class=&n&&requests&/span&&span class=&o&&.&/span&&span class=&n&&get&/span&&span class=&p&&(&/span&&span class=&n&&link&/span&&span class=&p&&,&/span& &span class=&n&&headers&/span&&span class=&o&&=&/span& &span class=&n&&headers&/span&
&span class=&nb&&print&/span& &span class=&p&&(&/span&&span class=&n&&r&/span&&span class=&o&&.&/span&&span class=&n&&text&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&上述代码获取了博客首页的网页HTML代码。首先import requests,使用requests.get(link, headers=headers)获取了网页。值得注意的是:&/p&&p&1. 用requests的headers可以伪装成浏览器访问&/p&&p&2. r是requests的Response回复对象,我们从中可以获取我们想要的信息。r.text是获取的网页内容代码。&/p&&p&运行完上述代码后,我们得到的结果是:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-0dcd9f9fb977eaf149e0_b.jpg& data-rawwidth=&415& data-rawheight=&114& class=&content_image& width=&415&&&/figure&&p&&br&&/p&&h2&3. 第二步:提取需要的数据&/h2&&div class=&highlight&&&pre&&code class=&language-python3&&&span&&/span&&span class=&ch&&#!/usr/bin/python&/span&
&span class=&c1&&# coding: utf-8&/span&
&span class=&kn&&import&/span& &span class=&nn&&requests&/span&
&span class=&kn&&from&/span& &span class=&nn&&bs4&/span& &span class=&k&&import&/span& &span class=&n&&BeautifulSoup&/span&
&span class=&c1&&#从bs4这个库中导入BeautifulSoup&/span&
&span class=&n&&link&/span& &span class=&o&&=&/span& &span class=&s2&&&http://www.santostang.com/&&/span&
&span class=&n&&headers&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&&span class=&s1&&'User-Agent'&/span& &span class=&p&&:&/span& &span class=&s1&&'Mozilla/5.0 (W U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/ Firefox/3.5.6'&/span&&span class=&p&&}&/span&
&span class=&n&&r&/span& &span class=&o&&=&/span& &span class=&n&&requests&/span&&span class=&o&&.&/span&&span class=&n&&get&/span&&span class=&p&&(&/span&&span class=&n&&link&/span&&span class=&p&&,&/span& &span class=&n&&headers&/span&&span class=&o&&=&/span& &span class=&n&&headers&/span&&span class=&p&&)&/span&
&span class=&n&&soup&/span& &span class=&o&&=&/span& &span class=&n&&BeautifulSoup&/span&&span class=&p&&(&/span&&span class=&n&&r&/span&&span class=&o&&.&/span&&span class=&n&&text&/span&&span class=&p&&,&/span& &span class=&s2&&&lxml&&/span&&span class=&p&&)&/span&
&span class=&c1&&#使用BeautifulSoup解析这段代码&/span&
&span class=&n&&title&/span& &span class=&o&&=&/span& &span class=&n&&soup&/span&&span class=&o&&.&/span&&span class=&n&&find&/span&&span class=&p&&(&/span&&span class=&s2&&&h1&&/span&&span class=&p&&,&/span& &span class=&n&&class_&/span&&span class=&o&&=&/span&&span class=&s2&&&post-title&&/span&&span class=&p&&)&/span&&span class=&o&&.&/span&&span class=&n&&a&/span&&span class=&o&&.&/span&&span class=&n&&text&/span&&span class=&o&&.&/span&&span class=&n&&strip&/span&&span class=&p&&()&/span&
&span class=&nb&&print&/span& &span class=&p&&(&/span&&span class=&n&&title&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&在获取到整个页面的HTML代码后,我们需要从整个网页中提取第一篇文章的标题。&/p&&p&这里用到beautifulsoup这个库了对爬下来的页面进行解析,首先我们需要导入这个库,from bs4 import BeautifulSoup。然后,把HTML代码转化为soup对象,接下来就是用soup.find(&h1&,class_=&post-title&).a.text.strip(),得到第一篇文章的标题,并且打印出来。&/p&&p&对初学者来说,beautifulsoup从网页中提取需要的数据,更加简单易用。&/p&&p&那么,我们是怎么从那么长的代码中准确找到标题的位置呢?&/p&&p&这里就要隆重介绍Chrome浏览器的“检查(审查元素)”功能了。下面介绍一下找到需要元素的步骤:&/p&&p&步骤一:使用Chrome浏览器,打开博客首页&a href=&https://link.zhihu.com/?target=http%3A//www.santostang.com& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&santostang.com&/span&&span class=&invisible&&&/span&&/a&。右键网页页面,在弹出的对话框中,点击“检查”选项。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-360a607f6d91e1cb6ef128af71c6ef4d_b.jpg& data-rawwidth=&203& data-rawheight=&221& class=&content_image& width=&203&&&/figure&&p&步骤二:出现如下图所示的审查元素功能。点击左上角的鼠标键,然后在页面上点击想要的数据,下面的Elements就会出现相应的code所在的地方,就定位到你想要的元素了。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-aaad67e966f9b_b.jpg& data-rawwidth=&415& data-rawheight=&239& class=&content_image& width=&415&&&/figure&&p&步骤三:在代码中找到标蓝色的地方,为&h1 class=”post-title”&&a&echarts学习笔记(2) – 同一页面多图表&/a&。于是,我们可以用soup.find(&h1&,class_=&post-title&).a.text.strip()提取出该博文的标题了。&/p&&p&&br&&/p&&h2&&b&4. 第三步:储存数据&/b&&/h2&&div class=&highlight&&&pre&&code class=&language-python3&&&span&&/span&&span class=&kn&&import&/span& &span class=&nn&&requests&/span&
&span class=&kn&&from&/span& &span class=&nn&&bs4&/span& &span class=&k&&import&/span& &span class=&n&&BeautifulSoup&/span&
&span class=&c1&&#从bs4这个库中导入BeautifulSoup&/span&
&span class=&n&&link&/span& &span class=&o&&=&/span& &span class=&s2&&&http://www.santostang.com/&&/span&
&span class=&n&&headers&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&&span class=&s1&&'User-Agent'&/span& &span class=&p&&:&/span& &span class=&s1&&'Mozilla/5.0 (W U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/ Firefox/3.5.6'&/span&&span class=&p&&}&/span&
&span class=&n&&r&/span& &span class=&o&&=&/span& &span class=&n&&requests&/span&&span class=&o&&.&/span&&span class=&n&&get&/span&&span class=&p&&(&/span&&span class=&n&&link&/span&&span class=&p&&,&/span& &span class=&n&&headers&/span&&span class=&o&&=&/span& &span class=&n&&headers&/span&&span class=&p&&)&/span&
&span class=&n&&soup&/span& &span class=&o&&=&/span& &span class=&n&&BeautifulSoup&/span&&span class=&p&&(&/span&&span class=&n&&r&/span&&span class=&o&&.&/span&&span class=&n&&text&/span&&span class=&p&&,&/span& &span class=&s2&&&lxml&&/span&&span class=&p&&)&/span&
&span class=&c1&&#使用BeautifulSoup解析这段代码&/span&
&span class=&n&&title&/span& &span class=&o&&=&/span& &span class=&n&&soup&/span&&span class=&o&&.&/span&&span class=&n&&find&/span&&span class=&p&&(&/span&&span class=&s2&&&h1&&/span&&span class=&p&&,&/span& &span class=&n&&class_&/span&&span class=&o&&=&/span&&span class=&s2&&&post-title&&/span&&span class=&p&&)&/span&&span class=&o&&.&/span&&span class=&n&&a&/span&&span class=&o&&.&/span&&span class=&n&&text&/span&&span class=&o&&.&/span&&span class=&n&&strip&/span&&span class=&p&&()&/span&
&span class=&nb&&print&/span& &span class=&p&&(&/span&&span class=&n&&title&/span&&span class=&p&&)&/span&
&span class=&k&&with&/span& &span class=&nb&&open&/span&&span class=&p&&(&/span&&span class=&s1&&'title.txt'&/span&&span class=&p&&,&/span& &span class=&s2&&&a+&&/span&&span class=&p&&)&/span& &span class=&k&&as&/span& &span class=&n&&f&/span&&span class=&p&&:&/span&
&span class=&n&&f&/span&&span class=&o&&.&/span&&span class=&n&&write&/span&&span class=&p&&(&/span&&span class=&n&&title&/span&&span class=&p&&)&/span&
&span class=&n&&f&/span&&span class=&o&&.&/span&&span class=&n&&close&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&储存到本地的txt文件也非常简单,在第二步的基础上,加上三行代码,就可以把这个字符串,保存在text里,并存到本地。txt文件地址应该和你的python文件在同一文件夹。&/p&&p&返回文件夹中,打开'title.txt'文件,可以看到里面的内容,如下图所示:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-71c21b5e2_b.jpg& data-rawwidth=&415& data-rawheight=&160& class=&content_image& width=&415&&&/figure&&p&&br&&/p&&h2&&b&一波硬广:&/b&&/h2&&p&&b&本文节选自图书《Python 网络爬虫:从入门到实践》第二章:编写你的第一个爬虫,由机械工业出版社出版。&/b&&/p&&p&本书主要分为三部分:基础部分(第1~6章)、进阶部分(第7~12章)和项目实践部分(第13~16章),以此来针对不同类型的读者。如果你是Python爬虫的初学者,那么可以先学习基础部分,这部分每一章的最后都有自我实践题,读者可以通过实践题熟悉编写Python爬虫代码。如果你已经对Python爬虫有所了解,但是在实践中遇到了各种问题,那么可以直接学习进阶部分,这部分为你在爬虫实践中遇到的问题提供了解决方案。本书最后的项目实践部分是让你在学习Python爬虫后,可以通过在真实网站中练习来消化和吸收Python爬虫的知识。 &/p&&p&这本书相对网络上的学习比较系统化,希望大家能支持!&/p&&p&&b&京东链接:&/b&&a href=&https://link.zhihu.com/?target=http%3A//item.jd.com/.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《Python网络爬虫从入门到实践》(唐松,陈智铨)【摘要 书评 试读】- 京东图书&/a&&/p&&p&&b&当当链接:&/b&&a href=&https://link.zhihu.com/?target=http%3A//product.dangdang.com/.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《Python网络爬虫从入门到实践》(唐松 陈智铨)【简介_书评_在线阅读】 - 当当图书&/a&&/p&
爬虫在大数据时代占据了重要的位置,在网上有大量的公开数据可以轻松获取。爬虫入门其实非常简单,就算你是编程小白,也可以轻松爬下一些网站。下面就以爬取笔者的个人博客网站()为例,教大家学会一个简单的爬虫。。一方面,由于这个网站的…
&figure&&img src=&https://pic4.zhimg.com/v2-47fbb3b7d0f8e4a387f4d3c6ed8303df_b.jpg& data-rawwidth=&680& data-rawheight=&453& class=&origin_image zh-lightbox-thumb& width=&680& data-original=&https://pic4.zhimg.com/v2-47fbb3b7d0f8e4a387f4d3c6ed8303df_r.jpg&&&/figure&&p&项目已在最大同性交友平台开源:&a href=&http://link.zhihu.com/?target=https%3A//github.com/Croxxpwn/CroxxProxyPool& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Croxxpwn/CroxxProxyPool&/a&&/p&&p&&br&&/p&&p&这个项目可以直接使用,README中有简单的Usage,项目中还附带了一个爬虫sample可供参考。&/p&&p&&br&&/p&&p&########&/p&&p&写在前面&/p&&p&&br&&/p&&p&这篇文章虽然实现的是一个“轻量级”的代理池,但是相比其他人的实现还是稍微复杂,因为我们除了实现代理池功能还添加了这些功能:&/p&&ul&&li&实现了线程安全,使多线程爬虫能更方便地使用&/li&&li&使用堆管理代理,尽可能降低同一IP的访问频率&/li&&li&“递归”爬取代理网站,突破了代理网站的IP限制&/li&&li&因为设计地相对完善,使用起来也更加简单&/li&&/ul&&p&&br&&/p&&p&叉鸽在这方面其实也算是萌新,因为最近爬链家的时候被卡IP,在网上没有找到合适的轮子于是就自己造了一个,欢迎真正的大佬提出意见。&/p&&p&&br&&/p&&p&########&/p&&p&&br&&/p&&p&下面是正文。&/p&&p&&br&&/p&&p&刚接触爬虫不久的小伙伴在爬大型网站的时候,一定都遇到过因为同一IP访问太频繁而被限制的情况。叉鸽在刚学习爬虫的时候,遇到这种情况就会选择限制访问频率。显然,使用这种方法爬完大型网站的信息简直是天方夜谭。那么有没有更好的方式呢?&/p&&p&&br&&/p&&p&答案当然是有的(不然我写这篇文章干啥)。在爬虫被限制IP的时候,我们可以使用代理服务器来“切换”IP进行访问。当然,对于爬虫的访问量来说,只有几个代理服务器还是不够的。目前很多网站都提供大量的免费http/https代理服务器,比如比较有名的“西刺代理”。我们可以使用这些服务器绕过IP检测。但是,免费的IP代理服务往往不稳定、无法保证可用性。因此,我们需要编写一个“代理池”来测试并管理从免费代理网站上得到的服务器。下面,叉鸽将带大家使用Python编写一个“轻量级”的IP代理池。&/p&&p&&br&&/p&&p&在编写代理池之前,我们先思考一下实现代理池需要哪些步骤:&/p&&ol&&li&从代理网上爬取代理服务器的ip地址与端口号&/li&&li&测试爬取到的代理服务器&/li&&li&将测试成功地代理服务器保存下来以供爬虫使用&/li&&/ol&&p&&br&&/p&&p&从上面看来,实现一个代理池似乎不是很困难。不过,一个为爬虫服务的代理池还需要考虑线程安全问题。因为使用代理之后(特别是免费代理),网站访问速度可能会变得很慢。单线程的爬虫此时根本无法满足爬取的效率要求。当涉及到多线程时,我们就要考虑线程安全问题。&/p&&p&&br&&/p&&p&当大致思路成型之后,我们就可以开始编写代理池了。&/p&&p&&br&&/p&&p&首先,我们需要编写代理类Proxy用来保存代理服务器有用的信息:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&class Proxy(object):
def __init__(self,host,port,source):
self.host = host
self.port = port
self.source = source
self.refresh()
def refresh(self):
self.timestamp = datetime.now()
def toURL(self):
return self.host+':'+self.port
def __lt__(self,x):
return self.timestamp & x.timestamp
def __str__(self):
return '&Proxy host = %s port = %s source = %s timestamp = %s&' % (self.host,self.port,self.source,self.timestamp)
def __repr__(self):
return str(self)
&/code&&/pre&&/div&&p&我们的Proxy类主要用来保存代理服务器的ip地址、端口号以及最后一次被使用的时间。为什么要保存最后一次被使用的时间呢?因为当可用的代理服务器很多时,我们尽量挑选使用间隔时间最长的服务器来尽可能避免同一IP频繁访问;保存最后访问时间后,我们可以使用堆方便地进行管理。为了使用Python自带的堆模块,我们重载了__lt__函数来对两个Proxy进行大小的比较。除此之外,我们还编写了refresh方法用来更新最后访问时间、toURL方法方便生成代理服务器的URL。&/p&&p&&br&&/p&&p&接下来我们来编写保存Proxy使用的堆ProxyHeap类:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&class ProxyHeap(object):
def __init__(self):
self.__heap = []
def push(self,item):
item.refresh()
heapq.heappush(self.__heap,item)
def pop(self):
return heapq.heappop(self.__heap)
def empty(self):
if len(self.__heap) == 0:
return True
return False
def length(self):
return len(self.__heap)
def __str__(self):
s = '&ProxyHeap ( %s items in all )' % len((self.__heap))
for item in self.__heap:
s += '\n' + str(item)
&/code&&/pre&&/div&&p&ProxyHeap类使用一个私有列表__heap作为堆的储存结构,对外开放了push方法用来入堆(push时需要更新Proxy最后一次被访问的时间)、pop方法用来获取距上一次使用时间最长的Proxy(同时出堆)、empty方法返回堆是否为空、length方法返回堆中代理个数。&/p&&p&&br&&/p&&p&实现了代理堆之后,我们就可以继续实现代理池ProxyPool:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&class ProxyPool(object):
__instance = None
def __init__(self):
def __new__(cls,*args,**kwargs):
if ProxyPool.__instance is None:
ProxyPool.__instance = super(ProxyPool,cls).__new__(cls,*args,**kwargs)
ProxyPool.__instance.__start = False
ProxyPool.__instance.__proxyheap = None
ProxyPool.__instance.__mutex = threading.Lock()
ProxyPool.__instance.__cond = threading.Condition(ProxyPool.__instance.__mutex)
return ProxyPool.__instance
def __str__(self):
return '&ProxyPool object(singleton)&'
def __repr__(self):
return str(self)
def start(self,delay = 10 * 60,source = 'xicidaili',ssl = False,debug = False):
print 'ProxyPool start !'
if self.__start:
'ProxyPool has already started. Do not start it again!'
self.__start = True
self.__proxyset = set()
self.__proxyheap = ProxyHeap()
#self.__timer = threading.Timer(delay,self.refresh,(source,debug))
self.refresh(delay,source,ssl,debug)
def pop(self,debug = False):
if self.__start:
self.__cond.acquire()
while self.__proxyheap is None:
self.__cond.wait()
while self.__proxyheap.empty():
self.__cond.wait()
item = self.__proxyheap.pop()
self.__proxyset.remove(item.toURL())
print 'POP : ',item,'[ %s LEFT ]' % (self.__proxyheap.length(),)
self.__cond.notify()
self.__cond.release()
return item
print 'Please start ProxyPool first !'
return None
def push(self,item,debug = False):
if self.__start:
self.__cond.acquire()
if item.toURL() not in self.__proxyset:
self.__proxyset.add(item.toURL())
flag = self.__proxyheap.push(item)
print 'PUSH : ',item,'[ %s LEFT ]' % (self.__proxyheap.length(),)
print 'UNPUSH[REPEAT] : ',item,'[ %s LEFT ]' % (self.__proxyheap.length(),)
self.__cond.notify()
self.__cond.release()
def refresh(self,delay,source,ssl,debug):
proxylist = getProxyList(source,ssl,debug)
for p in proxylist:
threading.Thread(target = TestProxy,kwargs = {'proxy':p,'ssl':ssl,'debug':debug,'pp':self}).start()
self.__timer = threading.Timer(delay,self.refresh,(delay,source,ssl,debug))
self.__timer.start()
def length(self):
return self.__proxyheap.length()
&/code&&/pre&&/div&&p&代理池的代码看上去很长很复杂,主要是因为我们需要使其保证线程安全并使用单例模式。__instance、__init__、__new__用来实现ProxyPool的单例。线程安全我们使用了Condition的方式实现。push与pop方法除了保证线程安全以外,还使用集合来对加入的Proxy去重(因为代理网站一般会实时刷新,因此很容易爬取到相同的代理)。refresh方法用来爬取代理网站,其中,getProxyList函数(接下来实现)用来从代理网站上爬取代理服务器的信息,TestProxy(接下来实现)用来测试爬取到的代理服务器的可用性;TestProxy需要使用多线程实现,因为测试代理服务器可用性本身也是很慢的过程。refresh方法中我们还使用的定时器,保证refresh方法可以每隔一段时间就执行一次。start方法用来启动代理池,即唤醒refresh方法,让它开始爬取并测试代理服务器。&/p&&p&&br&&/p&&p&代理池类编写完后,我们来实现爬取代理网站信息的getProxyList方法:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def getProxyList(source,ssl,debug,proxy = None):
proxylist = []
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0. Safari/537.36',
proxies = {}
if proxy is not None:
proxies = {
'http':proxy.toURL(),
'https':proxy.toURL(),
print '[ Fetching proxies with proxy ! ]'
if source=='xicidaili':
if proxy is not None:
pagerange = 51
pagerange = 11
url = &http://www.xicidaili.com/wn/&+str(random.randint(1,pagerange))
url = &http://www.xicidaili.com/wt/&+str(random.randint(1,pagerange))
res = requests.get(url,headers=headers,proxies = proxies)
html = etree.HTML(res.text)
ip_list_tables = html.xpath(&//table[@id='ip_list']&)
if len(ip_list_tables)==0:
if proxy is None:
print 'Crawler : Get No IP List !'
print '[ Proxy failed to fetch another proxy table ! %s ]' % (proxy,)
ip_list_table = html.xpath(&//table[@id='ip_list']&)[0]
for tr in ip_list_table.xpath(&//tr&)[1:]:
tds = tr.xpath('td')[1:3]
proxylist.append(Proxy(tds[0].text,tds[1].text,source))
print 'Get Proxy List ( %s items) :' % ( len(proxylist) ,)
for item in proxylist:
print item
if proxy is not None:
print '[ Proxy secceed to fetch another proxy table ! %s ]' % (proxy,)
print 'Failed to fetch proxy table caused by network probloms.'
return proxylist
&/code&&/pre&&/div&&p&getProxyList函数看上去很长,其实原理很简单。使用requests获取页面html内容,然后使用lxml模块的xpath来从中提取代理服务器的host与ip。将其保存在列表中并返回(有人会问为什么不使用数据库保存,因为代理网站上的服务器是实时刷新的,而且每个代理服务器的寿命都有限,每次使用时我们只需要实时爬即可,没必要对其长久保存)。&/p&&p&&br&&/p&&p&在getProxyList函数中有一个细节,就是我们在其中为使用代理预留了参数。为什么要这样做呢?因为代理网站同样会限制IP的访问频率,而且免费的代理可用性很低,比如西刺虽然每页提供了100条代理,但是可用的一般只有5-15条,因此我们想大量从西刺上爬取代理服务器信息,我们也需要使用代理(这个代理可以使用获取到的免费代理)。&/p&&p&&br&&/p&&p&接下来我们需要实现测试代理的可用性函数TestProxy:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def TestProxy(proxy,ssl = False,url = None,debug = False,pp = None):
if url is None:
url = 'https://www.baidu.com'
url = 'http://www.hao123.com'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0. Safari/537.36',
proxies = {
'http':proxy.toURL(),
'https':proxy.toURL(),
print 'Testing Proxy',proxy,'ssl = %s url = %s' % (ssl,url)
res = requests.get(url,headers=headers,proxies=proxies)
print '[BAD]',proxy
return False
print '[GOOD]',proxy
if pp is not None:
pp.push(proxy,debug=debug)
proxylist = getProxyList(proxy.source,ssl,debug,proxy=proxy)
for p in proxylist:
threading.Thread(target = TestProxy,kwargs = {'proxy':p,'ssl':ssl,'debug':debug,'pp':pp}).start()
return True
&/code&&/pre&&/div&&p&TestProxy实现的也很简单,主要过程就是使用代理访问百度或hao123,如果访问成功则说明代理有效,可以将其加入代理池,否则直接抛弃这条代理。不过我为TestProxy添加了一些模式,例如测试ssl协议或http协议、是仅测试代理还是测试后将其加入代理池等(还有每个函数都有的debug方法来输出执行过程调试信息)。同时,在测试代理可用后,我们直接使用该代理去从代理网站爬取其他代理信息。如上文所说,这样做是为了突破代理网站的ip检测,提高找到可用代理的效率(实际上,免费代理池的效率瓶颈大多都在找可用代理的时候,在第一个版本中我没如此递归爬取,寻找可用代理的效率非常低,还容易被代理网站封ip;实现了递归爬取的版本当可用代理滚雪球式增长之后,寻找可用代理的效率提升了2-10倍)。&/p&&p&&br&&/p&&p&这样,我们的“轻量级”代理池就写完了。相比其他一些轻量级开源的免费代理池而言,我们的代理池有如下的优点:&/p&&ul&&li&实现了线程安全,使多线程爬虫能更方便地使用&/li&&li&使用堆管理代理,尽可能降低同一IP的访问频率&/li&&li&“递归”爬取代理网站,突破了代理网站的IP限制&/li&&li&因为设计地相对完善,使用起来也更加简单&/li&&/ul&&p&&br&&/p&&p&看完文章懒得自己实现的小伙伴可以从我的Github上clone项目。其中只有CroxxProxyPool.py是需要引入的,其他Python模块是我用来测试使用的和一个简单的爬取链家中地铁线周边二手房链接的例子方便使用的读者参考。&/p&&p&&br&&/p&&p&这个项目的Github地址:&a href=&http://link.zhihu.com/?target=https%3A//github.com/Croxxpwn/CroxxProxyPool& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Croxxpwn/CroxxProxyPool&/a&&/p&&p&&br&&/p&&p&下面附上简单的Usage:&/p&&p&&br&&/p&&p&1.Import CroxxProxyPool&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&from CroxxProxyPool import ProxyPool
&/code&&/pre&&/div&&p&2.Get instance&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&pp = ProxyPool()
# get ProxyPool instance (ProxyPool is a singleton. You can only have ONE instance.)
&/code&&/pre&&/div&&p&3.Start crawling proxies&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&pp.start(delay = 10 * 60,ssl = True)
# start crawling proxies
&/code&&/pre&&/div&&p&4.Get a proxy by pop()&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&proxy = pp.pop()
# get a proxy
&/code&&/pre&&/div&&p&5.Push the proxy back after using it&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&pp.push(proxy)
# push the proxy back to ProxyPool after using it
&/code&&/pre&&/div&&p&&br&&/p&&p&使用起来还是很方便的吧(虽然写的时候相比其它人的复杂了一些)。&/p&&p&&br&&/p&&p&这个项目我目前正在使用,因此最近也会更新,感谢大家的关注。&/p&&p&&br&&/p&&p&最后安利自己的一个娱(zhuang)乐(bi)向回答:&a href=&https://www.zhihu.com/question//answer/?group_id=333120& class=&internal&&叉鸽:想知道大家都用python写过哪些有趣的脚本?&/a&&/p&
项目已在最大同性交友平台开源: 这个项目可以直接使用,README中有简单的Usage,项目中还附带了一个爬虫sample可供参考。 ########写在前面 这篇文章虽然实现的是一个“轻量级”的代理池,但是相比其他人的实现还是稍微复杂,因为…
&figure&&img src=&https://pic1.zhimg.com/v2-d31ffac5fd385f74a3fb8c65cbb94cf0_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic1.zhimg.com/v2-d31ffac5fd385f74a3fb8c65cbb94cf0_r.jpg&&&/figure&&blockquote&&i&本文首发:&u&&a href=&https://link.zhihu.com/?target=http%3A//zkeeer.space/%3Fp%3D395& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ZKeeer’s Blog——简单爬虫的通用步骤&/a&&/u&&br&代码基于 python3.5&br&多图预警,长文预警&/i& &i&知识点很多,适合小白,大神绕路&/i& &i&文章不详细的地方,以后会补充。&/i& &i&&b&欢迎署名和不署名转载&/b&&/i&&/blockquote&&h2&&i&目录:&/i&&/h2&&figure&&img src=&https://pic4.zhimg.com/v2-e2e0f6895dbd07ba19f8c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&437& data-rawheight=&597& class=&origin_image zh-lightbox-thumb& w

我要回帖

更多关于 网页无法审查元素 的文章

 

随机推荐