python打造爬虫代理池过程解析


Posted in Python onAugust 15, 2019

最近在使用爬虫爬取数据时,经常会返回403代码,大致意思是该IP访问过于频繁,被限制访问。限制IP访问网站最常用的反爬手段了,其实破解也很容易,就是在爬取网站是使用代理即可,这个IP被限制了,就使用其他的IP。对于高大上的公司来说,他们基本都使用收费的代理,基本不会有什么问题,比较稳定。像我这样的矮矬穷,肯定是用不起收费的代理。一般都是使用国内免费的代理,网上也有很多提供免费的代理。

很多人都是从网上爬取一批免费的代理IP,存放在存储媒介中,例如excel文件或者数据库。定时维护代理,保证代理可用。这个做法有个缺点,有些机器上并没有装有excel或者mysql、redis等数据库,这就导致了的代理池无法正常使用。

我之前是做java开发的,经常会把一些常用的数据放在ArrayList中,使用起来非常方便,效率高,因此借鉴之前在java方面的经验,将代理IP爬取下来存放在list列表中中,将list列表当做一个代理池,经常维护这个池里的代理。

我经常爬取免费代理的网站xicidaili swei360等,这些免费的代理足够我使用了,能够应付大多数的爬虫工作。爬取过程需要用到requests和pyquery库,没有安装的同学自行安装。

首先介绍下爬取xicidaili网站的过程, 要先定义一个方法用于抓取xicidaili网站的,参数有两个,一个是url,另外一个是要爬取代理网页的页数,也就是要爬几页,方法如下:

def get_xicidaili_proxy(url,page):
  for i in range(1,page):
    headers = {
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
    response = requests.get(url + str(i), headers=headers)

    html = response.text
    doc = pq(html)
    ip_list = doc('#ip_list')('tr:gt(0)').items()
    for item in ip_list:
      ip = item.find('td:nth-child(2)').text()
      port = item.find('td:nth-child(3)').text()
      http_type = item.find('td:nth-child(6)').text()
      proxy_ip = http_type + "://" + ip + ":" + port
      if http_type == 'HTTP':
        http_proxy_pool.append(proxy_ip)
      elif http_type == 'HTTPS':
        https_proxy_pool.append(proxy_ip)
      # print(proxy_ip)

定义了http_proxy_pool和https_proxy_pool两个list变量,用于存储http类型和https类型的代理。 使用PyQuery根据css伪选择器提取出ip,端口和http类型信息,并按照http:// + ip+port的方式组合成一个字符串,存储在已经定义好的http_proxy_tool和https_proxy_pool变量中。

爬取swei360网站代理的方法就不贴出来了,原理和爬取xicidaili网站是一样的。

一个代理在使用之前要判断是否可用,我们使用request的get请求的返回代码判断代理是否可用,返回200,就说明代理可用,返回其他的代码就表示代理不可用,代码如下:

def detect_proxy(test_url,http_type,proxy):
  headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
  proxy={
    http_type : proxy
  }
  try:
    response = requests.get(test_url,proxies=proxy,headers=headers)
    if response.status_code in [200]:
      print('代理可用',proxy)
      return True
    else:
      print('代理不可用', proxy);
      delete_proxy(http_type,proxy)
      return False
  except(requests.exceptions.ProxyError,RequestException):
    print('代理不可用', proxy)
    delete_proxy(http_type, proxy)
    return False

定义了detect_proxy方法用于检测代理是否可用,有三个参数,分别是测试网址,代理类型(http和https)和代理IP。当requests的请求返回200代码时,就表示该代理可用,返回True,否则就是不可用,返回False。当遇到request异常或者其他的错误也认为代理不可用,返回False。对于不可用的代理,要从代理池中删除。

从代理池中获取代理时,我们使用的是从代理池中随机返回一个代理,这样就避免经常使用一个代理,从而遭到拒绝访问。代码如下:

def get_https_proxy():
  proxy_ip = random.choice(https_proxy_pool)
  return proxy_ip

def get_http_proxy():
  proxy_ip = random.choice(http_proxy_pool)
  return proxy_ip

为了保证代理的可用,当检测到一个代理不可用时,要及时的清理掉。就是从http_proxy_pool和https_proxy_pool列表中删除。

一个简单的爬虫代理池已经搭建好,总结下爬虫代理池搭建的过程:

  • 从免费的代理网站上爬取代理信息,存放在列表中。
  • 提供从代理池中随机获取代理的方法。http类型的网站要使用http类型的代理,https类型的网站要使用https类型的代理,因此分别提供获取http和https类型代理的方法。
  • 提供检测代理是否可用的方法,代理可用返回True,不可用返回False。
  • 提供删除代理的方法。

这个代理池其实相当的简单,有一个弊端就是在检测代理是否可用时,如果返回的不是200代码就认为代理不可用,返回其他代码的情况有很多,例如网络不可用、测试网站不可访问等。比较好的做法是给每个代理设置一个分值,例如10分,如果检测到不可用就减1,当分数为0时,就确定该代理不可用,直接从代理池中移除。检测到代理可用,就将分数设为10分。

这种做法给每个检测到不可用代理一个改邪归正的机会,不至于一刀切的抛弃掉。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python使用shelve模块实现简单数据存储的方法
May 20 Python
Python 图像处理: 生成二维高斯分布蒙版的实例
Jul 04 Python
python判断自身是否正在运行的方法
Aug 08 Python
详解字符串在Python内部是如何省内存的
Feb 03 Python
python调用HEG工具批量处理MODIS数据的方法及注意事项
Feb 18 Python
PyCharm永久激活方式(推荐)
Sep 22 Python
python模拟实现分发扑克牌
Apr 22 Python
Python+PyQt5+MySQL实现天气管理系统
Jun 16 Python
Python datetime 如何处理时区信息
Sep 02 Python
Numpy(Pandas)删除全为零的列的方法
Sep 11 Python
Python中相见恨晚的技巧
Apr 13 Python
OpenCV图像变换之傅里叶变换的一些应用
Jul 26 Python
使用selenium和pyquery爬取京东商品列表过程解析
Aug 15 #Python
如何爬取通过ajax加载数据的网站
Aug 15 #Python
Python K最近邻从原理到实现的方法
Aug 15 #Python
Python数据可视化 pyecharts实现各种统计图表过程详解
Aug 15 #Python
浅谈Python 敏感词过滤的实现
Aug 15 #Python
pycharm创建scrapy项目教程及遇到的坑解析
Aug 15 #Python
通过selenium抓取某东的TT购买记录并分析趋势过程解析
Aug 15 #Python
You might like
PHP实现多条件查询实例代码
2010/07/17 PHP
PHP发明人谈MVC和网站设计架构 貌似他不支持php用mvc
2011/06/04 PHP
PHP和MySql中32位和64位的整形范围是多少
2016/02/18 PHP
php获取本机真实IP地址实例代码
2016/03/31 PHP
php实现在新浪云中使用imagick生成缩略图并上传的方法
2016/09/26 PHP
PHP如何获取当前主机、域名、网址、路径、端口等参数
2017/06/09 PHP
thinkphp5.0整合phpsocketio完整攻略(绕坑)
2018/10/12 PHP
PHP封装XML和JSON格式数据接口操作示例
2019/03/06 PHP
php swoole多进程/多线程用法示例【基于php7nts版】
2019/08/12 PHP
关于Yii2框架跑脚本时内存泄漏问题的分析与解决
2019/12/01 PHP
5个可以帮你理解JavaScript核心闭包和作用域的小例子
2014/10/08 Javascript
使用JavaScript实现连续滚动字幕效果的方法
2015/07/07 Javascript
关于JavaScript的变量的数据类型的判断方法
2015/08/14 Javascript
深入理解JS函数的参数(arguments)的使用
2016/05/28 Javascript
再谈Javascript中的异步以及如何异步
2016/08/19 Javascript
Vue2单一事件管理组件通信
2017/05/09 Javascript
微信小程序中做用户登录与登录态维护的实现详解
2017/05/17 Javascript
解决Angular2 router.navigate刷新页面的问题
2018/08/31 Javascript
Node.js 使用axios读写influxDB的方法示例
2018/10/26 Javascript
vue router 通过路由来实现切换头部标题功能
2019/04/24 Javascript
JS异步错误捕获的一些事小结
2019/04/26 Javascript
JS通过ajax + 多列布局 + 自动加载实现瀑布流效果
2019/05/30 Javascript
JavaScript本地储存:localStorage、sessionStorage、cookie的使用
2020/10/13 Javascript
简单理解Python中的装饰器
2015/07/31 Python
利用python实现命令行有道词典的方法示例
2017/01/31 Python
python socket网络编程之粘包问题详解
2018/04/28 Python
django自带的server 让外网主机访问方法
2018/05/14 Python
解决python tkinter界面卡死的问题
2019/07/17 Python
Python使用mongodb保存爬取豆瓣电影的数据过程解析
2019/08/14 Python
python实现opencv+scoket网络实时图传
2020/03/20 Python
Python pickle模块常用方法代码实例
2020/10/10 Python
CSS3绘制六边形的简单实现
2016/08/25 HTML / CSS
学习委员自我鉴定
2014/01/13 职场文书
门诊手术室工作制度
2014/01/30 职场文书
2014年入党积极分子学习三中全会思想汇报
2014/09/13 职场文书
高中运动会广播稿
2014/09/16 职场文书