zoukankan      html  css  js  c++  java
  • python代理池的构建3——爬取代理ip

    上篇博客地址python代理池的构建2——代理ip是否可用的处理和检查  

    一、基础爬虫模块(Base_spider.py)

    #-*-coding:utf-8-*-
    '''
    目标: 实现可以指定不同URL列表,分组的XPATH和详情的XPATH,从不同页面上提取代理的IP,端口号和区域的通用爬虫;
    步骤:
    1.在base_ spider.py文件中,定义 一个BaseSpider类, 继承object
    
    2.提供三个类成员变量:
    
        urls:代理IP网址的URL的列表
        
        group_ xpath:分组XPATH,获取包含代理IP信息标签列表的XPATH
    
        detail. xpath:组内XPATH,获取代理IP详情的信息XPATH,格式为: {'ip':'xx', 'pot':'xx','area':'xx'}
    
    3.提供初始方法,传入爬虫URL列表,分组XPATH,详情(组内)XPATH4.对外提供-个获取代理IP的方法,遍历URL列表,获取URL
    
        根据发送请求,获取页面数据
    
        解析页面,提取数据,封装为Proxy对象
        
        返回Proxy对象列表
    
    '''
    
    import requests
    import sys
    from lxml import etree
    sys.path.append("..")   #提供要导入的模块路径,之前博客讲过怎么使用
    sys.path.append("../..")
    from utils.http import get_requests_headers
    from domain import Proxy
    
    class BaseSpider(object):  #定义一个最基础的爬虫,后面爬取专门网站的爬虫继承这个基础爬虫
        urls = []
        group_xpath = ''  #因为我们用的lxml模块解析页面,所以要传入分组xpath和细节xpath
        detail_xpath = {}  #这个细节xpath就是ip在页面的位置,端口在页面的位置等等
    
        def __init__(self,urls=[],group_xpath='',detail_xpath={}):
            if urls:
                self.urls = urls
    
            if group_xpath:
                self.group_xpath = group_xpath
    
            if detail_xpath:
                self.detail_xpath = detail_xpath
    
        def get_page_from_url(self,url):
            response = requests.get(url,headers=get_requests_headers()) 
            #这个get_requests_headers方法是获取一个随机请求头,之前http.py模块定义过这个方法
            return response.content
    
        def get_first_list(self,li=[]):
            if len(li)!=0:
                return li[0]
            else :
                return ''
    
        def get_proxies_from_page(self,page):
            #这个就是把HTML页面给lxml,让它解析
            element = etree.HTML(page)
    
            trs = element.xpath(self.group_xpath)
            #print(trs)
            for tr in trs:
                #tr.xpath(self.detail_xpath['ip'])因为这一部分返回的是一个列表,而且如果我们直接写
                #tr.xpath(self.detail_xpath['ip'])[0],如果这个列表为空,他就会报错导致程序异常终止
                ip = self.get_first_list(tr.xpath(self.detail_xpath['ip']))
                port = self.get_first_list(tr.xpath(self.detail_xpath['port']))
                area = self.get_first_list(tr.xpath(self.detail_xpath['area']))
                proxy = Proxy(ip,port,area=area)
                print(proxy.__dict__) #这个dict函数就是把对象转化成字典类型输出,python内部函数
                yield proxy  #函数有了这个关键字,函数就是一个生成器函数。上篇博客讲过,会挂一下链接
    
        def get_proxies(self):
            for url in self.urls:
                # print(url)
                page = self.get_page_from_url(url)
                # print(page)
                proxies = self.get_proxies_from_page(page)
                yield from proxies
    
    if __name__ == '__main__': #用于测试这个这个模块
        # config = {
        #     'urls':{'http://www.ip3366.net/?stype=1&page={}'.format(i) for i in range(1,3)},
        #     'group_xpath':'//*[@id="list"]/table/tbody/tr',
        #     'detail_xpath':{
        #         'ip':'./td[1]/text()',
        #         'port':'./td[2]/text()',
        #         'area':'./td[6]/text()'
        #     }
        # }
        #
        # spider = BaseSpider(**config)
        # for proxy in spider.get_proxies():
        #     print(proxy)
        url = 'http://www.66ip.cn/4.html'
        response = requests.get(url,headers=get_requests_headers())
        print(response.content.decode('GBK'))

    python 引用(import)文件夹下的py文件 

    二、专门针对几个网站的爬虫(proxy_spiders.py)

    #-*-coding:utf-8-*-
    from base_spider import BaseSpider
    
    
    class XiciSpider(BaseSpider):
        urls = {'https://www.xicidaili.com/nn/{}'.format(i) for i in range(1,2)}
        group_xpath = '//*[@id="ip_list"]/tr[position()>1]'
        detail_xpath = {
            'ip':'./td[2]/text()',
            'port':'./td[3]/text()',
            'area':'./td[4]/a/text()'
        }
    
    class ProxylistplusSpider(BaseSpider):
        urls = {'https://list.proxylistplus.com/Fresh-HTTP-Proxy-List-{}'.format(i) for i in range(1,2)}
        group_xpath = '//*[@id="page"]/table[2]/tr[position()>5]'
        detail_xpath = {
            'ip':'./td[2]/text()',
            'port':'./td[3]/text()',
            'area':'./td[5]/text()'
        }
    
    class KuaidailiSpider(BaseSpider):
        urls = {'https://www.kuaidaili.com/free/inha/{}'.format(i) for i in range(1,4)}
        group_xpath = '//*[@id="list"]/table/tbody/tr'
        detail_xpath = {
            'ip':'./td[1]/text()',
            'port':'./td[2]/text()',
            'area':'./td[5]/text()'
    
        }
    
    class ip66Spider(BaseSpider):
        urls = {'http://www.66ip.cn/{}.html'.format(i) for i in range(1,4)}
        group_xpath = '//*[@id="main"]/div/div[1]/table/tr[position()>1]'
        detail_xpath = {
            'ip':'./td[1]/text()',
            'port':'./td[2]/text()',
            'area':'./td[3]/text()'
        }
    
    if __name__ == '__main__':
        pass
        # spider = XiciSpider()
        # spider = ProxylistplusSpider()
        # spider = KuaidailiSpider()
        #  spider = ip66Spider()
        #  for proxy in spider.get_proxies():
        #      print(proxy)

    我写的时候就没遇到反爬。。。。我也不知道为啥。。。。我就传了一个请求头headers

    三、运行这几个爬虫(run_spiders.py)

    #-*-coding:utf-8-*-
    import sys
    import importlib
    import schedule
    import time
    from gevent import monkey
    monkey.patch_all()  #打上猴子补丁,这个我博客下面有这一方面解释链接
    
    from gevent.pool import Pool   #导入协程池
    #可能有人会问为什么要用协程,因为requests.get()请求的时候会等待时间,我们可以利用这一部分时间做其他事情
    sys.path.append("../..")
    sys.path.append("..")
    from settings import SPIDERS
    from proxy_validate.httpbin_validator import check_proxy
    from db.mongo_pool import MongoPool  #要把可用代理IP存入mongodb数据库
    from utils.log import logger
    from settings import RUN_SPIDERS_INTERVAL #这些都是settings.py模块的一些变量
    
    class RunSpiders(object):
    
        def __init__(self):
            self.mongo_pool = MongoPool()  #创建一个数据库对象,这个是我们写的模块,可以看python代理池的构建4——mongdb数据库的增删改查
            self.coroutine_pool = Pool() #创建协程池
    
        def get_spider_from_settings(self):
            for full_class_name in SPIDERS:  #下面这一部分就是动态导入模块,我会给出相应博客链接去解释他
                module_name,class_name=full_class_name.rsplit('.',maxsplit=1)
                module = importlib.import_module(module_name)
                clss = getattr(module,class_name)
                spider = clss()
                #print(spider)
                yield spider
    
        def run(self):
            spiders = self.get_spider_from_settings()
    
            for spider in spiders:  #开启多协程去分别运行多个爬虫
                self.coroutine_pool.apply_async(self.run_one,args=(spider,))
    
            self.coroutine_pool.join()  #等全部爬虫都运行完,再结束这个函数
    
        def run_one(self,spider):
            try:   #try一下,以防某个爬虫失败导入异常,从而程序异常结束
                for proxy in spider.get_proxies():
                    proxy = check_proxy(proxy)
                    if proxy.speed != -1:
                        self.mongo_pool.insert_one(proxy)  #这个就是把这一个代理ip信息插入到数据库里面
            except Exception as ex:
                logger.exception(ex)
    
        @classmethod  #定义一个类方法,之后可以通过类名来调用
        def start(cls):  #这个cls参数,是它自己就带的
            rs = RunSpiders()
            rs.run()
            schedule.every(RUN_SPIDERS_INTERVAL).hours.do(rs.run)  
            #这个意思就是每隔RUN_SPIDERS_INTERVAL小时,就执行一遍rs.run函数
            while True:
                schedule.run_pending()  #这个就是检查时间到两个小时了没
                time.sleep(60)
    
    if __name__ == '__main__':   #检查本模块是否可用
        RunSpiders.start()
        # rs = RunSpiders()
        # rs.run()

    四、关于代码一些问题解决链接:

    协程gevent模块和猴子补丁

    python中schedule模块的简单使用 || importlib.import_module动态导入模块

    Python中“*”和“**”的用法 || yield的用法 || ‘$in’和'$nin' || python @property的含义

    python代理池的构建4——mongdb数据库的增删改查

    五、python代理池的构建的其他链接

    python代理池的构建5——对mongodb数据库里面代理ip检查

    python代理池的构建4——mongdb数据库的增删改查

    python代理池的构建2——代理ip是否可用的处理和检查

    python代理池的构建1——代理IP类的构建,以及配置文件、日志文件、requests请求头

  • 相关阅读:
    打印出乘法表
    python小练习1
    JavaScript 两个变量互换
    纯css3 画一个小猪佩奇
    箭头函数
    点击获取li下标的几种方式
    再见!!!!!!
    十月一前期
    大家好!!!!!!
    雕刻技
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/12174610.html
Copyright © 2011-2022 走看看