IP代理池2.0版本,加入多进程以及多线程

这次对之前的代理池1.0版本进行了升级,可用性大大增加了,也增加了一些IP源头的获取,包括西刺高匿代理前50页的IP抓取,还有对于TXT文件里面的IP存入数据库的操作,因为楼主是测试了免费的代理之后再也不想用了,就直接去淘宝买了20几块一个月,还能接受,因为返回的IP是在txt文件里,所以有了这个操作。顺便提一下,之前抓取了西刺免费2000多个IP,测出来能用的只有20个左右,妈的,亮瞎我的眼,好了,先看代码框架。

Paste_Image.png

先看封装的数据库操作

from pymongo import MongoClient,errors
from _datetime import datetime,timedelta

class mogo_queue(object):
    OUTSTANDING = 1  ##初始状态
    PROCESSING = 2  ##测试过后的状态

    def __init__(self, db, collection):
        self.client = MongoClient()
        self.database = self.client[db]  # 链接数据库
        self.db = self.database[collection]  # 链接数据库里面这个表
    def __bool__(self):
        """
        这个函数,我的理解是如果下面的表达为真,则整个类为真
        至于有什么用,后面我会注明的(如果我的理解有误,请指点出来谢谢,我也是Python新手)
        $ne的意思是不匹配
        """
        record = self.db.find_one(
            {'status': {'$ne': self.PROCESSING}}
        )
        return True if record else False
    def push_ip_url(self,url):
        self.db.insert({'_id':url})
        print('IP链接{}插入成功'.format(url))
    def find_url(self):#找到所有代理的url
        url_list=[]
        for i in self.db.find():
            url= i['_id']
            url_list.append(url)
        return url_list
    def find_proxy(self):
        proxy_list = []  # 用来接收从数据库查找到的所有代理
        for i in self.db.find():
            proxy = i['proxy']
            proxy_list.append(proxy)
        return proxy_list
    def push_ip(self,ip,port,proxy):#把代理插进数据库的操作
        try:
            self.db.insert({'_id':ip,'port':port,'proxy':proxy,'status':self.OUTSTANDING})
            print(proxy,'代理插入成功')
        except errors.DuplicateKeyError as e:#对于重复的ip不能插入
            print(proxy,'已经存在队列中')
    def find_one_ip(self):
        record = self.db.find_and_modify(
            query={'status': self.OUTSTANDING},#改变状态,防止另外的进程也车市同一个ip
            update={'$set': {'status': self.PROCESSING,}}
        )
        if record:
            return record['proxy']
        else:
            raise KeyError
    def status_setting(self):
        record = self.db.find({'status':self.PROCESSING})#找到所有状态为2的代理,
        #就是之前测试过的,以备重新测试,毕竟很多IP存活率不高
        #print(record)
        for i in record:
            print(i)
            id=i["_id"]
            #query={'status':self.PROCESSING},
            self.db.update({'_id':id},{'$set': {'status': self.OUTSTANDING }})#该状态为1,
            #重新测试
            print('代理',id,'更改成功')
        # if record:
        #     return record
    def delete_proxy(self,proxy):
        """这个函数是更新已完成的URL完成"""
        self.db.delete_one({'proxy': proxy})
        print('无效代理{}删除成功'.format(proxy))

下面是test文件

import requests
from pymongo import MongoClient
import re
from bs4 import BeautifulSoup
from  mogodb_operate import mogo_queue
from proxy_request import  request
url_queue = mogo_queue('ip_database','ip_link_collection')
ip_queue = mogo_queue('ip_database','proxy_collection')

class ip_operator():
    @staticmethod
    def insert_xici_url(page):
        urls = ['http://www.xicidaili.com/nn/{}'.format(str(i)) for i in range(page)]
      #构造西刺网前面page页的URL
        for url in urls:
            #print(url)
            url_queue.push_ip_url(url)#插进URL数据库

    @staticmethod
    def catch_ip_xici():#爬取西刺网前面50页的免费IP
        ip_url=url_queue.find_url()
        for url in ip_url:
            data = request.get(url,3)
            all_data = BeautifulSoup(data.text, 'lxml')
            all_ip = all_data.find_all('tr', class_='odd')
            for i in all_ip:
                ip = i.find_all('td')[1].get_text()  # ip
                port = i.find_all('td')[2].get_text()  # 端口
                proxy = (ip + ':' + port).strip()  # 组成成proxy代理
                ip_queue.push_ip(ip,port,proxy)#插进数据库
    #ip_queue.find_one_ip()
    @staticmethod#本来还想把快代理的抓取也封装进来,
     然后测试了西刺之后,觉得免费IP就算了吧....,这段代码大家可以无视
    def insert_kuaidaili_url(page):
        urls=['http://www.kuaidaili.com/free/inha/{}/'.format(str(i)) for i in range(page)]
        for url in urls:
            url_queue.push_ip_url(url)
    #catch_url_ip()
    @staticmethod
    def insert_ip_text():#把txt文件里面的ip存进数据库
        f= open('C:\\Users\\admin\\Desktop\\ip_daili.txt',encoding='utf-8')
        data = f.read()
        proxy=data.split('\n')
        for i in proxy:
            proxie = i,
            ip =i.split(':')[0]# ip
            port =i.split(":")[1]   # 端口
            #proxie = str(ip)+':'+str(port),
            #print(ip,port,i)
            ip_queue.push_ip(ip,port,i)
        #print(proxy)
        f.close()



ip_operator.catch_ip_xici()
#爬西刺的代理,存进数据库以待检验
ip_operator().insert_ip_text()
#把txt文件里面保存的IP插进数数据库以待检验存进数据库以待检验

接下来是爬虫主程序,写了好久啊,哎,都是因为要爬文书网才写了这玩意

import requests
from pymongo import MongoClient
import threading
from bs4 import BeautifulSoup
import time
import re
from  mogodb_operate import mogo_queue
url = 'http://ip.chinaz.com/getip.aspx'#这个是用于测试IP有效性的网站,
IP正常情况下会返回IP,以及IP所在地址
import multiprocessing
ip_queue = mogo_queue('ip_database','proxy_collection')#链接到储存IP的数据库
def ip_catch(max_threads=9):

    def test_effictive_ip():
        while True:#不断循环,找到数据进行测试
            try:
                proxy = ip_queue.find_one_ip()#提取IP,准备测试
   
                try:
                    proxies = {'http':'http://{}'.format(proxy),
                                            'https':'http://{}'.format(proxy),}
                    html = requests.get(url,proxies=proxies,timeout=1)

                    status_number = re.findall(r'\d\d\d', str(html))[0]#提取网页返回码
                    re_ip = re.findall(r'\{ip',html.text)#有些ip极其恶心,
                    虽然返回的是200数字,
                    表示正常,实则是bad request,这里去除掉
                    #print(re_ip)
                    if status_number==str(200):
                        if re_ip:

                            #检验代理是否能正常使用
                            print('网页返回状态码:',html,proxy,'代理有效,地址是:',html.text)
                        else:
                            ip_queue.delete_proxy(proxy)
                    else:
                        ip_queue.delete_proxy(proxy)
                except:
                    ip_queue.delete_proxy(proxy)
            except KeyError:

                print('队列没有数据了')
                break
                #print(proxy,'代理无效')
    threads = []
    while threads or ip_queue:
        """
                这儿crawl_queue用上了,就是我们__bool__函数的作用,
                为真则代表我们MongoDB队列里面还有IP没检测完,
                也就是状态依然是没有改变,还有没被测试过的IP
                threads 或者 为真都代表我们还没下载完成,程序就会继续执行
        """
        for thread in threads:
            if not thread.is_alive():  ##is_alive是判断是否为空,不是空则在队列中删掉
                    threads.remove(thread)
        while len(threads) < max_threads :  ##线程池中的线程少于max_threads 或者 crawl_qeue时
            thread = threading.Thread(target=test_effictive_ip)  ##创建线程
            thread.setDaemon(True)  ##设置守护线程
            thread.start()  ##启动线程
            threads.append(thread)  ##添加进线程队列
        time.sleep(5)
def process_crawler():
    process = []
    num_cpus = multiprocessing.cpu_count()
    print('将会启动进程数为:', num_cpus)
    for i in range(num_cpus):
        p = multiprocessing.Process(target=ip_catch)  ##创建进程
        p.start()  ##启动进程
        process.append(p)  ##添加进进程队列
    for p in process:
        p.join()  ##等待进程队列里面的进程结束


if __name__ == "__main__":
    ip_queue.status_setting()#重置状态,以便测试
    process_crawler()

于是我在淘宝每次提取5000个IP,都有差不多300个能有,已经满足了,以后找到更好的IP代理源再分享出来,上张运行图和测试过后的图,开始之前是5000,最后只剩几百,源头问题真的很重要

Paste_Image.png
Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,587评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,401评论 25 707
  • 一阵风 带着小小只的蒲公英 来到这方土地 掬一勺清水 满满的 寄思绪于秋叶 行囊里的白衬衫 是无法回头的旅行 期待...
    Lavender苏阅读 282评论 0 2
  • 作为一部外传电影,主演们的知名度并不是很高,尤其是《星球大战》的系列电影在我国的流行度并不高,只被认为它是一个美...
    王廿阅读 683评论 0 1
  • 早上六点五十,老刘起床上班,刷牙,洗脸,上厕所,七点十分出门,骑上自行车十分钟到了单位食堂,十分钟吃完饭,...
    酢新羽阅读 209评论 0 1