Python搭建代理IP池实现获取IP的方法


Posted in Python onOctober 27, 2019

使用爬虫时,大部分网站都有一定的反爬措施,有些网站会限制每个 IP 的访问速度或访问次数,超出了它的限制你的 IP 就会被封掉。对于访问速度的处理比较简单,只要间隔一段时间爬取一次就行了,避免频繁访问;而对于访问次数,就需要使用代理 IP 来帮忙了,使用多个代理 IP 轮换着去访问目标网址可以有效地解决问题。

目前网上有很多的代理服务网站提供代理服务,也提供一些免费的代理,但可用性较差,如果需求较高可以购买付费代理,可用性较好。

因此我们可以自己构建代理池,从各种代理服务网站中获取代理 IP,并检测其可用性(使用一个稳定的网址来检测,最好是自己将要爬取的网站),再保存到数据库中,需要使用的时候再调用。

代码地址:https://github.com/Stevengz/Proxy_pool

另外三篇:
Python搭建代理IP池(二)- 存储 IP
Python搭建代理IP池(三)- 检测 IP
Python搭建代理IP池(四)- 接口设置与整体调度

本文介绍的则是构建代理 IP 池的第一步:获取 IP

使用的库:requests、pyquery

几个能提供免费代理的代理服务网站(排名不分先后):

厂商名称 地址
66代理 http://www.66ip.cn/
西刺代理 https://www.xicidaili.com
全网代理 http://www.goubanjia.com
云代理 http://www.ip3366.net
IP海 http://www.iphai.com
快代理 https://www.kuaidaili.com
免费代理IP库 http://ip.jiangxianli.com

代理服务网站 Crawler

代理获取的相关代码,把从每个网站提取 IP 的方法都放到一起,然后运行时只要调用相关方法即可

为了实现灵活,将获取代理的一个个方法统一定义一个规范,如统一定义以 crawl 开头,这样扩展的时候只需要添加 crawl 开头的方法即可

在这里实现了几个示例,如抓取代理 66、西刺代理、云代理、快代理 四个免费代理网站,这些方法都定义成生成器,通过 yield 返回。首先将网页获取,然后用 PyQuery 解析,解析出 IP 加端口形式的代理再返回

crawler.py

import json
import re
from utils import get_page
from pyquery import PyQuery as pq

# 元类
class ProxyMetaclass(type):
 def __new__(cls, name, bases, attrs):
  count = 0
  attrs['__CrawlFunc__'] = []
  for k, v in attrs.items():
   if 'crawl_' in k:
    attrs['__CrawlFunc__'].append(k)
    count += 1
  attrs['__CrawlFuncCount__'] = count
  return type.__new__(cls, name, bases, attrs)

class Crawler(object, metaclass=ProxyMetaclass):
 def get_proxies(self, callback):
  proxies = []
  for proxy in eval("self.{}()".format(callback)):
   print('成功获取到代理', proxy)
   proxies.append(proxy)
  return proxies

 def crawl_daili66(self, page_count=4):
  start_url = 'http://www.66ip.cn/{}.html'
  urls = [start_url.format(page) for page in range(1, page_count + 1)]
  for url in urls:
   print('Crawling', url)
   html = get_page(url)
   if html:
    doc = pq(html)
    trs = doc('.containerbox table tr:gt(0)').items()
    for tr in trs:
     ip = tr.find('td:nth-child(1)').text()
     port = tr.find('td:nth-child(2)').text()
     yield ':'.join([ip, port])

 def crawl_xicidaili(self):
  for i in range(1, 3):
   start_url = 'http://www.xicidaili.com/nn/{}'.format(i)
   headers = {
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Host':'www.xicidaili.com',
    'Referer':'http://www.xicidaili.com/nn/3',
    'Upgrade-Insecure-Requests':'1',
   }
   html = get_page(start_url, options=headers)
   if html:
    find_trs = re.compile('<tr class.*?>(.*?)</tr>', re.S)
    trs = find_trs.findall(html)
    for tr in trs:
     find_ip = re.compile('<td>(\d+\.\d+\.\d+\.\d+)</td>') 
     re_ip_address = find_ip.findall(tr)
     find_port = re.compile('<td>(\d+)</td>')
     re_port = find_port.findall(tr)
     for address,port in zip(re_ip_address, re_port):
      address_port = address+':'+port
      yield address_port.replace(' ','')

 def crawl_ip3366(self):
  for i in range(1, 4):
   start_url = 'http://www.ip3366.net/?stype=1&page={}'.format(i)
   html = get_page(start_url)
   if html:
    find_tr = re.compile('<tr>(.*?)</tr>', re.S)
    trs = find_tr.findall(html)
    for s in range(1, len(trs)):
     find_ip = re.compile('<td>(\d+\.\d+\.\d+\.\d+)</td>')
     re_ip_address = find_ip.findall(trs[s])
     find_port = re.compile('<td>(\d+)</td>')
     re_port = find_port.findall(trs[s])
     for address,port in zip(re_ip_address, re_port):
      address_port = address+':'+port
      yield address_port.replace(' ','')

 def crawl_kuaidaili(self):
  for i in range(1, 4):
   start_url = 'http://www.kuaidaili.com/free/inha/{}/'.format(i)
   html = get_page(start_url)
   if html:
    ip_address = re.compile('<td data-title="IP">(.*?)</td>') 
    re_ip_address = ip_address.findall(html)
    port = re.compile('<td data-title="PORT">(.*?)</td>')
    re_port = port.findall(html)
    for address,port in zip(re_ip_address, re_port):
     address_port = address+':'+port
     yield address_port.replace(' ','')

定义了一个 ProxyMetaclass,Crawl 类将它设置为元类,元类中实现了 new() 方法,遍历 attrs 变量即可获取类的所有方法信息,判断方法名前面是否是 crawl,是则将其加入到 CrawlFunc 属性中

代理网站的添加非常灵活,不仅可以添加免费代理,也可以添加付费代理,一些付费代理的提取方式类似,也通过 Web 的形式获取再进行解析,解析方式可能更加简单,如解析纯文本或 Json,解析之后以同样的方式返回,可以自行扩展

utils.py

import requests
from requests.exceptions import ConnectionError

base_headers = {
 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36',
 'Accept-Encoding': 'gzip, deflate, sdch',
 'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7'
}

def get_page(url, options={}):

 headers = dict(base_headers, **options)
 print('正在抓取', url)
 try:
  response = requests.get(url, headers=headers)
  print('抓取成功', url, response.status_code)
  if response.status_code == 200:
   return response.text
 except ConnectionError:
  print('抓取失败', url)
  return None

抓取网页内容的方法,访问链接成功后返回整个网页 HTML 内容,便于后续对网页具体内容的提取。封装成一个方法,让上面的 crawler 在抓取各个网站时调用

进行抓取

getter.py

from crawler import Crawler
from setting import *
import sys

class Getter():
 def __init__(self):
  self.crawler = Crawler()
 
 def run(self):
  print('获取器开始执行')
  for callback_label in range(self.crawler.__CrawlFuncCount__):
   callback = self.crawler.__CrawlFunc__[callback_label]
   # 获取代理
   all_ip = self.crawler.get_proxies(callback)

if __name__ == '__main__':
 get = Getter()
 get.run()

运行结果:

Python搭建代理IP池实现获取IP的方法

网站上的免费 IP 就被成功抓取下来了,至于能不能用,就有待验证了

整个过程其实就是一个普通的爬虫,而且没什么反爬措施,能到用代理 IP 的地步,代码里面的访问、抓取部分的细节应该都看得懂

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

Python 相关文章推荐
python 不关闭控制台的实现方法
Oct 23 Python
Python正则表达式如何进行字符串替换实例
Dec 28 Python
基于Python闭包及其作用域详解
Aug 28 Python
Python实现GUI学生信息管理系统
Apr 05 Python
TensorFlow如何实现反向传播
Feb 06 Python
python selenium 对浏览器标签页进行关闭和切换的方法
May 21 Python
numpy.random模块用法总结
May 27 Python
django admin组件使用方法详解
Jul 19 Python
Python基于BeautifulSoup和requests实现的爬虫功能示例
Aug 02 Python
浅析Python语言自带的数据结构有哪些
Aug 27 Python
Python实现鼠标自动在屏幕上随机移动功能
Mar 14 Python
Python如何在windows环境安装pip及rarfile
Jun 15 Python
详解python statistics模块及函数用法
Oct 27 #Python
在 Jupyter 中重新导入特定的 Python 文件(场景分析)
Oct 27 #Python
python自动结束mysql慢查询会话的实例代码
Oct 27 #Python
python实现输入任意一个大写字母生成金字塔的示例
Oct 27 #Python
python 爬虫百度地图的信息界面的实现方法
Oct 27 #Python
python用类实现文章敏感词的过滤方法示例
Oct 27 #Python
通过字符串导入 Python 模块的方法详解
Oct 27 #Python
You might like
PHP中去除换行解决办法小结(PHP_EOL)
2011/11/27 PHP
php class类的用法详细总结
2013/10/17 PHP
PHP中Memcache操作类及用法实例
2014/12/12 PHP
PHP目录操作实例总结
2016/09/27 PHP
关于ThinkPhp 框架表单验证及ajax验证问题
2017/07/19 PHP
PHP使用PDO操作sqlite数据库应用案例
2019/03/07 PHP
thinkphp框架类库扩展操作示例
2019/11/26 PHP
Javascript模块模式分析
2008/05/16 Javascript
JSON 编辑器实现代码
2009/12/06 Javascript
jQuery使用一个按钮控制图片的伸缩实现思路
2013/04/19 Javascript
ajax请求get与post的区别总结
2013/11/04 Javascript
js操作label给label赋值及取label的值示例
2013/11/07 Javascript
浅谈轻量级js模板引擎simplite
2015/02/13 Javascript
jQuery使用hide方法隐藏指定元素class样式用法实例
2015/03/30 Javascript
node.js连接mongoDB数据库 快速搭建自己的web服务
2016/04/17 Javascript
Javascript使用function创建类的两种方法(推荐)
2016/11/19 Javascript
vue v-model表单控件绑定详解
2017/05/17 Javascript
NodeJS收发GET和POST请求的示例代码
2017/08/25 NodeJs
jQuery中的类名选择器(.class)用法简单示例
2018/05/14 jQuery
jquery获取并修改触发事件的DOM元素示例【基于target 属性】
2019/10/10 jQuery
解决vue组件中click事件失效的问题
2019/11/09 Javascript
js判断浏览器的环境(pc端,移动端,还是微信浏览器)
2020/12/24 Javascript
angular中的post请求处理示例详解
2020/06/30 Javascript
python发送HTTP请求的方法小结
2015/07/08 Python
python数据预处理 :数据抽样解析
2020/02/24 Python
Python 如何定义匿名或内联函数
2020/08/01 Python
HTML5实现直播间评论滚动效果的代码
2020/05/27 HTML / CSS
Java基础知识面试要点
2016/07/29 面试题
汽车技术服务与营销专业在籍生自荐信
2013/09/28 职场文书
工程部经理岗位职责
2013/12/08 职场文书
违反课堂纪律检讨书
2014/01/19 职场文书
《月迹》教学反思
2014/02/19 职场文书
大学生全国两会报告感想
2014/03/17 职场文书
行政诉讼答辩状
2015/05/21 职场文书
法律讲堂观后感
2015/06/11 职场文书
JavaWeb 入门篇(3)ServletContext 详解 具体应用
2021/07/16 Java/Android