python构建IP代理池(Proxy Pool)[通俗易懂]

python构建IP代理池(Proxy Pool)[通俗易懂]基本原理代理实际上指的就是代理服务器,它的功能是代理网络用户去取得网络信息。也可以说它是网络信息的中转站。在我们正常请求一个网站时,是将请求发送给Web服务器,Web服务器把响应传回给我们。如果设置了代理服务器,实际上就是在本机和服务器之间搭建了一个桥,此时本机不是直接向Web服务器发起请求,而是向代理服务器发出请求,请求会发送给代理服务器,然后由代理服务器再发…

大家好,又见面了,我是你们的朋友全栈君。

基本原理

代理实际上指的就是代理服务器,它的功能是代理网络用户去取得网络信息 。也可以说它是网络信息的中转站 。

在我们正常请求一个网站时, 是将请求发送给 Web 服务器,Web 服务器把响应传回给我们 。 如果设置了代理服务器 , 实际上就是在本机和服务器之间搭建了一个桥, 此时本机不是直接 向 Web 服务器发起请求,而是向代理服务器发出请求,请求会发送给代理服务器,然后由代理服务器再发送给 Web 服务器,接着由代理服务器再把 Web 服务器返回的响应转发给本机。 这样我们同样可以正常访问网页,但这个过程中 Web 服务器识别出的真实 IP 就不再是我们本机的 IP 了,就成功实现了 IP 伪装,解决爬虫中封IP的难题。

了解代理服务器的基本原理后,我们不禁会想到几个问题,代理IP从何而来?如何保证代理可用性?代理如何存储?如何使用这些代理?

  • 获取代理IP: 爬取网站的免费代理。比如西刺、快代理之类有免费代理的网站, 但是这些免费代理大多数情况下都是不好用的,所以比较靠谱的方法是购买付费代理。当然,如果你有更好的代理接口也可以自己接入。
  • 检测IP代理可用性: 因为免费代理大部分是不可用的,所以采集回来的代理IP不能直接使用,可以写检测程序不断的去用这些代理访问一个稳定的网站,看是否可以正常使用。
  • 存储代理IP: 存储的代理IP首先要保证代理不重复 , 要检测代理的可用情况,还要动态实时处理每个代理,本文利用来MongoDB存储,当然也可用其他方式存储。
  • 使用代理:最简单的办法就是用 API 来提供对外服务的接口 。

 

IP代理池设计

我们了解了代理池的四大问题,所以我们可以根据这四个问题去分析设计一个代理池框架,我们可以分成四个模块。分别是获取模块、检测模块、存储模块、接口模块 。这样不仅有利于我们的维护,也使得可以更高效的完成我们的需求。

  • 架构图

python构建IP代理池(Proxy Pool)[通俗易懂]

代码模块

在这里只是简单的写出了代码模块的实现,并不完整不具有逻辑性,如想查看获取源代码,请移步到GitHub:https://github.com/wanhaiwei/proxypool

 

  • 获取模块
import requests
import chardet
import traceback
from lxml import etree

class Downloader(object):
    def __init__(self):
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
        }

    def download(self, url):
        print('正在下载页面:{}'.format(url))
        try:
            resp = requests.get(url, headers=self.headers)
            resp.encoding = chardet.detect(resp.content)['encoding']

            if resp.status_code == 200:
                return self.xpath_parse(resp.text)

            else:
                raise ConnectionError
        except Exception:
            print('下载页面出错:{}'.format(url))
            traceback.print_exc()

    def xpath_parse(self, resp):
        try:
            page = etree.HTML(resp)
            trs = page.xpath('//div[@id="list"]/table/tbody/tr')
            proxy_list = []
            for tr in trs:
                ip = tr.xpath('./td[1]/text()')[0]
                port = tr.xpath('./td[2]/text()')[0]
                proxy = {
                    'proxy': ip + ':' + port
                }
                proxy_list.append(proxy)
            return proxy_list
        except Exception:
            print('解析IP地址出错')
            traceback.print_exc()

if __name__ == '__main__':
    print(Downloader().download('https://www.kuaidaili.com/free/inha/1/'))
  • 存储模块
import pymongo
from pymongo.errors import DuplicateKeyError


class MongoDB(object):
    def __init__(self):
        self.client = pymongo.MongoClient()
        self.db = self.client['proxypool3']
        self.proxies = self.db['proxies']
        self.proxies.ensure_index('proxy', unique=True)
        self.proxies.create_index()
                    #  createIndex()
    def insert(self, proxy):
        try:
            self.proxies.insert(proxy)
            print('插入成功:{}'.format(proxy))
        except DuplicateKeyError:
            pass

    def delete(self, conditions):
        self.proxies.remove(conditions)
        print('删除成功:{}'.format(conditions))

    def update(self, conditions, values):
        self.proxies.update(conditions, {"$set": values})
        print('更新成功:{},{}'.format(conditions,values))

    def get(self, count, conditions=None):
        conditions = conditions if conditions else {}
        count = int(count)
        items = self.proxies.find(conditions, limit=count).sort('delay', pymongo.ASCENDING)
        items = list(items)
        return items

    def get_count(self):
        return self.proxies.count({})


if __name__ == '__main__':
    m = MongoDB()
    print(m.get(3))
  • 检测模块
import requests
import time
import traceback
from requests.exceptions import ProxyError, ConnectionError
from db.mongo_db import MongoDB
from multiprocessing.pool import ThreadPool


def valid_many(proxy_list, method):
    pool = ThreadPool(16)

    for proxy in proxy_list:
        pool.apply_async(valid_one, args=(proxy, method))
    pool.close()
    pool.join()


def valid_one(proxy, method, url='https://www.baidu.com'):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
    }
    proxies = {
        'http': 'http://' + proxy['proxy'],
        'https': 'http://' + proxy['proxy']
    }

    try:
        start_time = time.time()
        # requests.packages.urllib3.disable_warnings()
        resp = requests.get(url, headers=headers, proxies=proxies, timeout=5, verify=False)
        delay = round(time.time() - start_time, 2)

        if resp.status_code == 200:
            proxy['delay'] = delay
            if method == 'insert':

                MongoDB().insert(proxy)
            elif method == 'check':
                MongoDB().update({'proxy': proxy['proxy']}, {'delay': proxy['delay']})
        else:
            if method == 'check':
                MongoDB().delete({'proxy': proxy['proxy']})
    except (ProxyError, ConnectionError):
        if method == 'check':
            MongoDB().delete({'proxy': proxy['proxy']})
    except Exception:
        traceback.print_exc()
  • API接口模块
import flask
import json
from db.mongo_db import MongoDB


app = flask.Flask(__name__)


@app.route('/one')
def get_one():
    proxies = MongoDB().get(1)
    result = [proxy['proxy'] for proxy in proxies]
    return json.dumps(result)


@app.route('/many')
def get_many():
    args = flask.request.args
    proxies = MongoDB().get(args['count'])
    result = [proxy['proxy'] for proxy in proxies]
    return json.dumps(result)

def run():
    app.run()
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/144823.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月18日 下午5:00
下一篇 2022年5月18日 下午5:20


相关推荐

  • touchesBegan等方法不执行

    touchesBegan等方法不执行今天写了一个自定义控件继承于UILabel,想要在上面添加点击事件,用touchesBegan等一系列方法实现,程序跑起来自信满满,突然发现程序不执行该方法,找了半天,了解到貌似touch事件只能被UIView捕获,然后把label的用户交互开启了(发现UIImageView和UILabel的交互默认是关闭的),就能让下面的view捕获到touch事件了

    2022年7月25日
    9
  • html 中 超链接的写法,网页超链接样式的CSS写法「建议收藏」

    html 中 超链接的写法,网页超链接样式的CSS写法「建议收藏」上一篇文章讲了母栏目后面两行子栏目的DIV布局,这篇文章讲导航做完之后我想在鼠标移到每个不同区域的超链接在颜色上给予变化。上图所示上上一篇文章的大概样式,颜色就不一一举例了,我现在现在是给了“男士”“女士”“养生”三个母栏目不同的颜色,为了好看一点,我想鼠标移动到“男士”后面的子栏目上面的颜色和“男士”的字体颜色一样,移到“女士”其后面的子栏目的超链接与“女士”的超链接颜色一样,“养生”同样的。先…

    2022年7月19日
    16
  • 什么是断点续传?前端如何实现文件的断点续传「建议收藏」

    什么是断点续传?前端如何实现文件的断点续传「建议收藏」什么是断点续传?就是下载文件时,不必重头开始下载,而是从指定的位置继续下载,这样的功能就叫做断点续传。断点续传的理解可以分为两部分:一部分是断点,一部分是续传。断点的由来是在下载过程中,将一个下载

    2022年7月3日
    115
  • java导出pdf模板_java模板导出PDF[通俗易懂]

    java导出pdf模板_java模板导出PDF[通俗易懂]本次完善综合特点:一对一,点对点的给对应的地方写值,比如模板里面放了个name标识,在程序里把“张三”赋给name,那么输出的pdf里面name的地方就变成了张三,准确方便快捷支持中文,可以使用自己下载的字体。支持图片:图片的大小范围可以在模板随意调,生成出来的图片不会超过范围。而且不需要根据坐标去算,程序里面自动计算的。支持多页模板,即使是好几页的模板,只要每个变量对应的范围确定好了,生成出来的…

    2022年5月10日
    44
  • TypeError: ‘builtin_function_or_method’ object is not subscriptable的一种错误情况

    TypeError: ‘builtin_function_or_method’ object is not subscriptable的一种错误情况TypeError builtin function or method objectisnots 的一种错误情况初学 python 今天在做练习时为一个 Error 苦恼了很久最终找到了解决方法错误代码块如下 defget new nums numbers input Well Idon tknowyourfav

    2025年11月28日
    10
  • SQL Server2008安装详细教程[通俗易懂]

    SQL Server2008安装详细教程[通俗易懂]1.将光盘文件解压成文件夹格式,(解压过程比较慢,请耐心等待);2.打开开始菜单的设置;3.打开设置后,点击更新和安全,然后进入;4.在Windows安全中心,将其关闭(注意我这里已经关闭了);5.然后再到安装包文件夹目录,找到setup.exe文件,右击,以管理员身份运行;6.右击运行后,会出来这个页面(如果没有出现这个页面,请直接跳转至第14步),然后点击下载并安装此功能,进入下一步;7.进入下一个页面后,你会发现它会出来一个正在下载所需的文件的页面,然后等待就行;8

    2022年6月23日
    53

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号