自建代理ip池

前言

为什么需要使用ip池?

当使用爬虫时,爬取一般的网站或者少量数据时,一些简单的爬虫就可实现。但对于那些反爬机制设置很好的网站而言,一个ip在一段时间内访问过多就会被临时封掉,所以我们需要设置多个ip代理来爬取需要的数据。

网上的代理ip有很多,付费免费的都有,这里主要爬取了两个免费代理ip网站:快代理66代理

正文

爬取ip数据

和平常爬虫一样,我们传入网址,然后分析返回的response,获取到我们需要的代表代理ip的数据,然后保存到本地,这里具体就不在赘述。

### 爬取快代理的ip数据
def get_ip_kdl(html):
    ip_list = []
    soup = BeautifulSoup(html,'html.parser')
    tr_list = soup.select('tbody tr')
    for tr in tr_list:
        ip_dict = {}
        td = tr.select('td')
        ip_dict['ip'] = td[0].get_text()       #ip
        ip_dict['port'] = td[1].get_text()     #端口
        ip_dict['ip_type'] = td[3].get_text()  #网络类型
        ip_dict['speed'] = td[5].get_text()    #响应速度
        ip_list.append(ip_dict)
    # print(ip_list)
    return ip_list

def kdl():
    url = 'https://www.kuaidaili.com/free/inha/'
    html = get_response(url).text
    ip_list = get_ip_kdl(html)
    return ip_list
###
def get_ip_66(html):
    ip_list = []
    soup = BeautifulSoup(html, 'html.parser')
    tr_list = soup.find_all('div',attrs={'align':'center'})[1].select('table tr')
    # print(tr_list)
    for tr in tr_list[1:]:
        ip_dict = {}
        ip_dict['ip'] = tr.select('td')[0].get_text()  # ip
        ip_dict['port'] = tr.select('td')[1].get_text()  # 端口
        ip_dict['ip_type'] = None  # 网络类型
        ip_dict['speed'] = None  # 响应速度
        ip_list.append(ip_dict)
    # print(ip_list)
    return ip_list

def ip66():
    url = 'http://www.66ip.cn/'
    html = get_response(url).text
    ip_list = get_ip_66(html)
    return ip_list

这里使用的是第三方库BeautifulSoup,需要自己安装依赖包。当然也可使用python自带的正则来寻找数据,哪种使用熟练方便使用哪种。

保存至本地

我们所需要的数据只有IP和PORT字段,故可将其组合起来放入到txt文件中,方便复制使用;将IP、PORT、响应速度等保存为json文件,方便读取。

###保存至本地(具体保存地址自行修改)
#存为json
def save_json(ip):
    ip_json = json.dumps(ip, ensure_ascii=False) + ",\n"
    with open(r'C:\Users\15394\Desktop\ip池.json','ab') as f:
        f.write(ip_json.encode('utf-8'))

#存为txt
def save_txt(ip):
    ip_type = ip['ip_type']
    port = ip['port']
    str_ip = ip['ip']
    if ip_type == None:
        ip_txt = 'http://' + str_ip + ':' + port + '\n'
    else:
        ip_type = ip_type.lower()
        ip_txt = ip_type + '://' + str_ip + ':' + port + '\n'
    with open(r'C:\Users\15394\Desktop\ip池.txt','ab') as f:
        f.write(ip_txt.encode('utf-8'))

判断ip有效性

ip数据爬取下来了,但由于是免费的,所以不能确定它的有效性,需要自己判断一下。

这里是使用代理ip去访问百度,若返回200的状态码,则表示此ip可用。

#判断ip是否有用
def useful(ip):
    baidu_url = 'https://www.baidu.com/'
    headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",}
    proxy = 'http://' + ip['ip'] + ':' + ip['port']
    proxies = {'http':proxy}
    response = requests.get(baidu_url,proxies=proxies,headers=headers)
    if response.status_code == 200:
        return True
    else:
        return False

也可访问http://icanhazip.com/来查看当前访问的ip。

全部代码

需自行安装requests、bs4依赖包

#!-*-coding:utf-8 -*-
# python3.7
# @Author:fuq666@qq.com
# Update time:2021.01.28
# Filename:爬取网上的免费ip来组成ip池(并判断是否有用)

import requests
from bs4 import BeautifulSoup
import json

def get_response(url):
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
    }
    response = requests.get(url,headers=headers)
    if response.status_code == 200:
        return response
    else:
        print("{}请求失败".format(url))

#快代理
def get_ip_kdl(html):
    ip_list = []
    soup = BeautifulSoup(html,'html.parser')
    tr_list = soup.select('tbody tr')
    for tr in tr_list:
        ip_dict = {}
        td = tr.select('td')
        ip_dict['ip'] = td[0].get_text()       #ip
        ip_dict['port'] = td[1].get_text()     #端口
        ip_dict['ip_type'] = td[3].get_text()  #网络类型
        ip_dict['speed'] = td[5].get_text()    #响应速度
        ip_list.append(ip_dict)
    # print(ip_list)
    return ip_list

def kdl():
    url = 'https://www.kuaidaili.com/free/inha/'
    html = get_response(url).text
    ip_list = get_ip_kdl(html)
    return ip_list

#66ip
def get_ip_66(html):
    ip_list = []
    soup = BeautifulSoup(html, 'html.parser')
    tr_list = soup.find_all('div',attrs={'align':'center'})[1].select('table tr')
    # print(tr_list)
    for tr in tr_list[1:]:
        ip_dict = {}
        ip_dict['ip'] = tr.select('td')[0].get_text()  # ip
        ip_dict['port'] = tr.select('td')[1].get_text()  # 端口
        ip_dict['ip_type'] = None  # 网络类型
        ip_dict['speed'] = None  # 响应速度
        ip_list.append(ip_dict)
    # print(ip_list)
    return ip_list

def ip66():
    url = 'http://www.66ip.cn/'
    html = get_response(url).text
    ip_list = get_ip_66(html)
    return ip_list

#判断ip是否有用
def useful(ip):
    baidu_url = 'https://www.baidu.com/'
    headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",}
    proxy = 'http://' + ip['ip'] + ':' + ip['port']
    proxies = {'http':proxy}
    response = requests.get(baidu_url,proxies=proxies,headers=headers)
    if response.status_code == 200:
        return True
    else:
        return False

#存为json
def save_json(ip):
    ip_json = json.dumps(ip, ensure_ascii=False) + ",\n"
    with open(r'C:\Users\15394\Desktop\ip池.json','ab') as f:
        f.write(ip_json.encode('utf-8'))

#存为txt
def save_txt(ip):
    ip_type = ip['ip_type']
    port = ip['port']
    str_ip = ip['ip']
    if ip_type == None:
        ip_txt = 'http://' + str_ip + ':' + port + '\n'
    else:
        ip_type = ip_type.lower()
        ip_txt = ip_type + '://' + str_ip + ':' + port + '\n'
    with open(r'C:\Users\15394\Desktop\ip池.txt','ab') as f:
        f.write(ip_txt.encode('utf-8'))

def main():
    ip_list_kdl = kdl()
    ip_list_66 = ip66()
    # ip_list_gbj = gbj()
    ip_list = ip_list_kdl + ip_list_66
    for ip in ip_list:
        if useful(ip):      #有效的ip
            save_json(ip)
            save_txt(ip)
        else:
            pass

if __name__ == '__main__':
    main()

注:

  • 上面两个免费的ip网站随时可能无妨访问,所以平时可多积累几个类似的网站,或者使用付费的ip网站,效果更好。
  • 爬取下来的ip仅仅代表当前可用,随时可能失效,所以在需要使用的时候再进行爬取。并且,在使用这些代理ip进行爬虫时,也可能已经处于失效状态。查看ip是否可用,可在电脑终端ping ip,若能ping通,则表示有效。
  • 最好在学习之时,才使用免费代理ip。

其他

如何在爬虫中使用代理ip

  • 使用requests库进行爬虫

    import requests
    proxies = {'http':'http://localhost:8888','https':'http://localhost:8888'}
    response = requests.get(url,proxies=proxies,verify=False)
    #可将代理ip放入列表中,然后使用random.choice随机选取一个ip,再变为字典,传入requests
    
  • 使用scrapy框架进行爬虫

    1. ip池的存放

      ip池可以列表形式存于settings.py中,也可放置于中间件middlewares.py文件中。

      IPPOOL = [
          {"ipaddr":"115.221.245.137:9999"},
          {"ipaddr":"175.42.128.86:9999"},
      ]
      
    2. 使用ip

      ip的使用是在中间件middlewares.py文件中。

      import random
      #ip池
      class ippool(Object):
          def __init__(self,ip=''):
              self.ip = ip
      
          def process_request(self,request,spider):
              use_ip = random.choice(IPPOOL)
              # print('当前ip是:',use_ip["ipaddr"])
              request.meta["proxy"] = "http://" + use_ip["ipaddr"]
      

      还需要在settings.py文件中打开这个中间件的注释

      DOWNLOADER_MIDDLEWARES = {
         # 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 100,
         'JD.middlewares.ippool':150,
      }
      

      注:当ip池IPPOOL放在settings.py文件中时,还需要在middlewares.py中引用他。

      from JD.settings import IPPOOL
      
posted @ 2021-01-31 18:12  F___Q  阅读(147)  评论(0)    收藏  举报