Python实时抓取最新的代理IP

有时候同一个IP去爬取同一网站上的内容,久了之后就会被该网站服务器屏蔽。解决方法就是更换IP。这个时候,在对方网站上,显示的不是我们真实地IP地址,而是代理服务器的IP地址。西刺代理http://www.xicidaili.com/nn/ 提供了很多可用的国内IP,云代理http://www.ip3366.net/提供了许多国外IP可以直接拿来使用。

但是这些代理有的短时间内可能就会失效,为了高效的使用代理,用Python实现一个爬虫,实时抓取代理,并将有效代理存入数据库或写入文件方便我们取用,并可以随时检测数据库和文件中的代理是否已经失效,将失效的代理删除。

  • 下面是python代码实现:
# -*- coding=utf-8 -*-
__author__ = 'yansong'
import re
import requests
from lxml import etree
import urllib2, time, datetime
from lxml import etree
import sqlite3,time
import sys
import chardet

reload(sys)
sys.setdefaultencoding('utf-8') #设置系统默认编码为utf-8

class myProxy():

    def __init__(self):
        self.user_agent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
        self.header = {"User-Agent": self.user_agent}  #请求头
        self.dbname="myproxy.db"     #数据库名
        self.now = time.strftime("%Y-%m-%d")

    #抓取国内高匿代理,并检查IP、PORT 是否可用,若可用则存入数据库,并写入文件,方便需要时取用
    def getXicidaili(self, num):
        nn_url = "http://www.xicidaili.com/nn/" + str(num)
        #国内高匿
        req = urllib2.Request(nn_url, headers=self.header)
        resp = urllib2.urlopen(req, timeout=10)
        content = resp.read()
        et = etree.HTML(content)  #将源码转换为能被XPath匹配的格式

        #网页源码中class 分开了奇偶两个class,使用lxml最方便的方式就是分开获取。刚开始使用一个方式获取,出现很多IP和port抓不到的情况,分开获取可以抓到全部的ip 和port
        result_even = et.xpath('//tr[@class=""]') #返回为一列表
        result_odd = et.xpath('//tr[@class="odd"]')
        for i in result_even:
            t1 = i.xpath("./td/text()")[:6]
            #print "IP:%s\tPort:%s\t Type:%s" % (t1[0], t1[1], t1[5])
            if self.isAlive(t1[0], t1[1], t1[5]):
                if t1[5] == 'HTTP':                   #区分代理IP类型,是 HTTP 还是HTTPS
                    proxies = {'http': 'http://' + t1[0] + ':' + t1[1]}
                else:
                    proxies = {'https': 'https://' + t1[0] + ':' + t1[1]}

                #检查IP是否可用,将可用的代理IP写入文件
                self.check_Proxy_IP(proxies)
                #pass
                self.insert_db(self.now,t1[0],t1[1],t1[5])
        for i in result_odd:
            t2 = i.xpath("./td/text()")[:2]
            #print "IP:%s\tPort:%s" % (t2[0], t2[1])
            if self.isAlive(t2[0], t2[1]):
                #pass
                self.insert_db(self.now,t2[0],t2[1],t[5])
                if t1[5] == 'HTTP':
                    proxies = {'http': 'http://' + t1[0] + ':' + t1[1]}
                else:
                    proxies = {'https': 'https://' + t1[0] + ':' + t1[1]}
                # 检查IP是否可用,将可用的代理IP写入文件
                self.check_Proxy_IP(proxies)

    #将可用的代理 IP、端口、类型 存进数据库,方便后续使用
    def insert_db(self,date,ip,port,type):
        dbname=self.dbname
        try:
            conn=sqlite3.connect(dbname)
        except:
            print "Error to open database%" %self.dbname
        create_tb='''
        CREATE TABLE IF NOT EXISTS MYPROXY
        (DATE TEXT,
        IP TEXT,
        PORT TEXT,
        TYPE TEXT
        );
        '''
        conn.execute(create_tb)
        insert_db_cmd='''
        INSERT INTO MYPROXY (DATE,IP,PORT,TYPE) VALUES ('%s','%s','%s','%s');
        ''' %(date,ip,port,type)
        conn.execute(insert_db_cmd)
        conn.commit()
        conn.close()


    #查看爬到的代理IP是否还能用
    def isAlive(self,ip,port,type):
        if type == 'HTTP':          #区分代理IP类型,是 HTTP 还是HTTPS
            proxy = {'http':ip+':'+port}
        else:
            proxy = {'https': ip + ':' + port}
        #print proxy

        proxy_support=urllib2.ProxyHandler(proxy)
        opener=urllib2.build_opener(proxy_support)
        urllib2.install_opener(opener)
        #使用代理访问腾讯官网,进行验证代理是否有效
        #test_url="http://www.qq.com"
        test_url = 'https://blog.csdn.net/qq_21933615/article/details/81089043'
        req=urllib2.Request(test_url,headers=self.header)
        try:
            #timeout 代理延时设置为5,
            resp=urllib2.urlopen(req,timeout=5)
            print resp.read()
            if resp.code == 200:  #返回码200代表成功
                print proxy
                print "work"
                return True
            else:
                print "not work"
                return False
        except :
            #print "Not work"
            return False


    #检查数据库中的代理是否依然生效,将失效代理从数据库从删除
    def check_db_pool(self):
        conn=sqlite3.connect(self.dbname)
        query_cmd='''
        select IP,PORT,TYPE from MYPROXY;
        '''
        cursor=conn.execute(query_cmd)
        for row in cursor:
            print "ip:", row[0]
            print "port  :", row[1]
            print "type  :",row[2]

            if not self.isAlive(row[0],row[1],row[2]):
                #代理失效, 要从数据库从删除
                delete_cmd='''
                delete from PROXY where IP='%s'
                ''' %row[0]
                print "delete IP %s in db" %row[0]
                conn.execute(delete_cmd)
                conn.commit()
        conn.close()


    #抓取国外代理
    def getFrom_ip3366(self,num):
        url='http://www.ip3366.net/?stype=1&page=' + str(num)  #http://www.ip3366.net/
        s=requests.get(url,headers=self.header)
        print s.status_code
        #print s.text    # 注意s.text  与 s.content 区别
        #typeEncode = sys.getfilesystemencoding()  ##系统默认编码
        #print typeEncode
        infoencode = chardet.detect(s.content).get('encoding', 'utf-8')  ##通过第3方模块来自动提取网页的编码
        html2 = s.content.decode(infoencode, 'ignore').encode('utf-8')  ##先转换成unicode编码,然后转换系统编码输出
        #print html2
        selector = etree.HTML(html2)
        content = selector.xpath('//tbody/tr')
        print content
        for i in content:
            print i
            t1 = i.xpath("./td/text()")
            print "IP:%s\tPort:%s\tType:%s" % (t1[0], t1[1],t1[3])
            if self.isAlive(t1[0], t1[1], t1[3]):
                if t1[5] == 'HTTP':
                    proxies = {'http': 'http://' + t1[0] + ':' + t1[1]}
                else:
                    proxies = {'https': 'https://' + t1[0] + ':' + t1[1]}
                print proxies

    #检查proxy.cfg文件中的代理IP是否依然生效,将可用的代理IP保留下来,不能用的IP去掉
    def validation(self):
        fp = open('proxy.cfg', 'r')
        lines=fp.readlines()
        print lines
        new_lines=[]
        for i in lines:
            x=eval(i.strip())
            print x
            s = requests.get(url='https://guyuan.anjuke.com/community/p1/', headers=self.header, proxies=x, timeout=10)
            print s.status_code
            if s.status_code == 200:
                new_lines.append(i)

        fp.close()
        new_lines=list(set(new_lines))
        with open('proxy.cfg','w') as fp:
            for i in new_lines:
                fp.write(i)


    #检查代理IP是否可用,可用的话就写入文件proxy.cfg
    def check_Proxy_IP(self, proxies):
        fp=open('proxy.cfg','a')
        #print proxies
        try:
            s=requests.get(url='http://www.qq.com',headers=self.header,proxies=proxies,timeout=10)
            print s.status_code
            if s.status_code==200:
                #print str(proxies)
                print proxies
                print 'work'
                fp.write(str(proxies))
                fp.write('\n')
                fp.close()
        except Exception,e:
            print e


if __name__ == "__main__":
    obj=myProxy()
    #obj.check_db_pool()
    #obj.validation()
    for i in range(50):
        #obj.getFrom_ip3366(i)
        obj.getXicidaili(i)

猜你喜欢

转载自blog.csdn.net/qq_21933615/article/details/81103095