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 相关文章推荐
pytyon 带有重复的全排列
Aug 13 Python
python使用7z解压apk包的方法
Apr 18 Python
python回调函数用法实例分析
May 09 Python
在 Python 应用中使用 MongoDB的方法
Jan 05 Python
Python实现两个list对应元素相减操作示例
Jun 09 Python
Python中用字符串调用函数或方法示例代码
Aug 04 Python
python 限制函数执行时间,自己实现timeout的实例
Jan 12 Python
PyCharm中如何直接使用Anaconda已安装的库
May 28 Python
opencv 图像轮廓的实现示例
Jul 08 Python
Python如何合并多个字典或映射
Jul 24 Python
使用numpngw和matplotlib生成png动画的示例代码
Jan 24 Python
理解python中装饰器的作用
Jul 21 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
《Re:从零开始的异世界生活 冰结之绊》
2020/04/09 日漫
基于MySQL分区性能的详细介绍
2013/05/02 PHP
php后台如何避免用户直接进入方法实例
2013/10/15 PHP
php简单的上传类分享
2016/05/15 PHP
php连接oracle数据库的方法(测试成功)
2016/05/26 PHP
phpmyadmin下载、安装、配置教程
2017/05/16 PHP
浅谈laravel 5.6 安装 windows上使用composer的安装过程
2019/10/18 PHP
CL vs ForZe BO5 第五场 2.13
2021/03/10 DOTA
js静态方法与实例方法分析
2011/07/04 Javascript
jquery动画4.升级版遮罩效果的图片走廊--带自动运行效果
2012/08/24 Javascript
前台js对象在后台转化java对象的问题探讨
2013/12/20 Javascript
js利用数组length属性清空和截短数组的小例子
2014/01/15 Javascript
基于jQuery通过jQuery.form.js插件使用ajax提交form表单
2015/08/17 Javascript
AngularJS实现表单手动验证和表单自动验证
2015/12/09 Javascript
Vue.JS入门教程之列表渲染
2016/12/01 Javascript
Webpack中css-loader和less-loader的使用教程
2017/04/27 Javascript
Vue2几种常见开局方式详解
2017/09/09 Javascript
vue 使用自定义指令实现表单校验的方法
2018/08/28 Javascript
[16:04]DOTA2海涛带你玩炸弹 9月5日更新内容详解
2014/09/05 DOTA
跟老齐学Python之玩转字符串(2)更新篇
2014/09/28 Python
详细介绍Python中的偏函数
2015/04/27 Python
Python网络爬虫出现乱码问题的解决方法
2017/01/05 Python
深入理解Python3中的http.client模块
2017/03/29 Python
浅谈Django中的数据库模型类-models.py(一对一的关系)
2018/05/30 Python
浅谈pycharm的xmx和xms设置方法
2018/12/03 Python
python列表list保留顺序去重的实例
2018/12/14 Python
python爬虫之快速对js内容进行破解
2019/07/09 Python
Python3以GitHub为例来实现模拟登录和爬取的实例讲解
2020/07/30 Python
python中os.remove()用法及注意事项
2021/01/31 Python
python中添加模块导入路径的方法
2021/02/03 Python
CSS3 制作绽放的莲花采用效果叠加实现
2013/01/31 HTML / CSS
英国索普公园票务和酒店套餐:Thorpe Breaks
2019/09/14 全球购物
《大江保卫战》教学反思
2014/04/11 职场文书
《春到梅花山》教学反思
2014/04/16 职场文书
德生BCL3000抢先使用感受和评价
2022/04/07 无线电
Java Spring Boot请求方式与请求映射过程分析
2022/06/25 Java/Android