当前位置: 首页 > 后端技术 > Python

27.Python快速开发分布式搜索引擎Scrapy精讲——通过自定义中间件全局随机改变代理IP

时间:2023-03-26 02:11:15 Python

[百度云搜索,搜索各种资料:http://www.lqkweb.com][搜索网盘,搜索各种资料:http://www.swpan.cn]只需要设置代理ip,定制一个中间软件,重写process_request方法,request.meta['proxy']="http://103.112.213.146:1080"设置代理IP中间件,注意在adc.daili_ip.sh_yong_ip的配置文件中注册中间件。sh_yong_ipimportsui_ji_hq_ipfromfake_useragentimportUserAgent#导入浏览器用户代理模块classRequestsUserAgentmiddware(object):#自定义浏览器代理中间件#中间件随机替换Requests请求头信息的User-Agent浏览器用户代理def__init__(self,crawler):super(RequestsUserAgentmiddware,self).__init__()#获取上层父类基类,__init__方法中的对象封装值self.ua=UserAgent()#实例化浏览器用户代理模块类self.ua_type=crawler.settings.get('RANDOM_UA_TYPE','random')#获取settings.py配置文件中RANDOM_UA_TYPE配置的浏览器类型,如果没有则默认为random,随机获取各种浏览器类型@classmethod#上面的函数使用了装饰器@classmethod,函数中有一个强制形参cls,用于接收当前类名deffrom_crawler(cls,crawler):#Overloadfrom_crawlermethodreturncls(crawler)#返回crawlercrawler类defprocess_request(self,request,spider):#Overloadprocess_requestmethoddefget_ua():#自定义函数,在浏览器代理对象browser中返回指定类型informationreturngetattr(self.ua,self.ua_type)sssf=get_ua()print('启用用户代理浏览器信息:{0}'.format(sssf))request.headers.setdefault('User-Agent',get_ua())#在Requests中添加浏览器代理信息requestclassMyproxiesSpiderMiddleware(object):#中间件随机替换IPdefprocess_request(self,request,spider):#重写process_request方法#从数据库中随机获取一个IPxieyi=request._get_url()#_get_url可以得到请求的URL,判断请求是什么协议,比如httpsprint(xieyi)dai_ip=sui_ji_hq_ip('http')#从数据库中随机获取一个代理IPrequest.meta['proxy']="http://{0}".format(dai_ip)#字符串格式设置代理IP#request.meta['proxy']="http://185.82.203.146:1080"设置代理IP随机数据库获取IP#!/usr/bin/envpython#-*-coding:utf8-*-importtimeimportrequestsfromadc.daili_ip.mysqimportshujukuasORMdefsuiji_ip(rst):"""callthis函数随机去数据库获取代理IP并返回IP,如果IP不可用则自动删除返回False"""atime=time.localtime(time.time()-240)#设置检测到的IP在多长时间内获取(单位秒)sudu='00:00:03'#设置访问速度小于等于的IP,单位(时分秒)默认为3秒dqatime="{0}-{1}-{2}{3}:{4}:{5}".format(atime.tm_year,atime.tm_mon,atime.tm_mday,atime.tm_hour,atime.tm_min,atime.tm_sec)#分别取格式化后的时间和日期拼接成一个完整的日期try:mysq=ORM.session()shuju=mysq.query(ORM.daili_ip.ip,ORM.daili_ip.port,ORM.daili_ip.xtype,ORM.daili_ip.seshi_ri_qi,ORM.daili_ip.connectTimeMs).from_statment("SELECTip,port,xtype,seshi_ri_qi,connectTimeMsFROMdaili_ipWHERExtype='{0}'ANDce_shi='{1}'ANDseshi_ri_qi>='{2}'ANDconnectTimeMs<='??{3}'ORDERBYRAND()LIMIT1".format(rst,'1',dqatime,sudu)).all()mysq.close()ifshuju:print('获取IP')else:print('获取IP失败,请检查获取条件')exceptExceptionase:print('代理IP数据查询出错')returnTrueip=shuju[0][0]duan_kou=shuju[0][1]print('启用代理IP,获取数据库ToIP:{0}'.format(shuju))http_url='{0}://image.baidu.com/'.format(rst)proxy_url='{0}://{1}:{2}'.format(rst,ip,duan_kou)headers={'Referer':http_url,'User-Agent':'Mozilla/5.0(WindowsNT10.0;WOW64;rv:54.0)Gecko/20100101Firefox/54.0',}print('启用代理IP,测试URL:{0}'.format(http_url))print('启用代理IP,测试header:{0}'.format(proxy_url))try:proxy_dict={'http':proxy_url}响应=请求。得到(http_url,proxies=proxy_dict,headers=headers)exceptExceptionase:print('启用代理IP,速度测试连接失败{0}'.format(e))print('启用代理IP,速度测试连接失败,当前IP不可用,删除当前ip!')fanhui=mysq.query(ORM.daili_ip).filter(ORM.daili_ip.ip==ip).delete()#删除不可用数据mysq.commit()mysq.close()iffanhui==1:print("成功删除当前IP")else:print('删除当前IP失败')returnFalseelse:code=response.status_code#获取状态sudu=str(response.elapsed)#如果code>=200且code<300,则获取响应时间:atime=time.localtime()dqatime="{0}-{1}-{2}{3}:{4}:{5}".format(atime.tm_year,atime.tm_mon,atime.tm_mday,atime.tm_hour,atime.tm_min,atime.tm_sec)#分别取格式化后的时间和日期拼接成一个完整的日期print('启用代理IP,测试代理ip--{0}{1}--可用状态--状态码--{2}'.format(ip,duan_kou,code))print('代理IP开启,当前IP正常,正在标记到数据库')fanhui=mysq.query(ORM.daili_ip).filter(ORM.daili_ip.ip==ip).update({"ce_shi":"1","seshi_ri_qi":dqatime,"connectTimeMs":sudu})mysq.commit()mysq.close()iffanhui==1:print('成功标记数据库可用IP!')else:print('无法将可用IP标记到数据库!!!')print('返回IP给爬虫:{0}:{1}'.format(ip,duan_kou))returnip+':'+duan_kouelse:print('EnableproxyIP,testproxyip--{0}{1}--StatusUnavailable--StatusCode--{2}'.format(ip,duan_kou,code))print('返回的状态码无效,当前IP正在从数据库中删除')fanhui=mysq.query(ORM.daili_ip).filter(ORM.daili_ip.ip==ip).delete()#删除无效数据mysq.commit()mysq.close()iffanhui==1:print('删除当前IP成功')else:print('删除当前IP失败')returnFalsedefsui_ji_hq_ip(rst):"""正式使用:调用该函数,接收一个一个参数协议,比如http循环到数据库获取IP,如果IP不可用则删除继续获取直到ip可用,然后返回ip值30分钟内循环获取有效IPofthetest"""n=Trueh=Nonewhilen:youxiao_ip=suiji_ip(rst)ifyouxiao_ip:h=youxiao_ipn=Falsereturnh#print(sui_ji_hq_ip('http'))数据库模块文件importsqlalchemyfromsqlalchemy.ext.declarativeimportdeclarative_basefromsqlalchemyimportColumn,Integer,String,ForeignKey,UniqueConstraint,Index,text,DATETIME,TIMEfromsqlalchemy.ormimportsessionmaker,relationshipfromsqlalchemyimportcreate_engineimportrequestsimportjsonimporttimeimportdatetime#配置数据库引擎信息ENGINE=create_engine("mysql+pymysql://root:279819@127.0.0.1:3306/cshi?charset=utf8",max_overflow=500,echo=True)Base=declarative_base()#创建SQLORM基类classdaili_ip(Base):#ip池设计表__tablename__='daili_ip'id=Column(Integer,primary_key=True,autoincrement=True)ip=Column(String(300),unique=True)#IPport=Column(String(300))#portcity=Column(String(300))#cityisp=Column(String(300))#operatorconnectTimeMs=Column(TIME())#speedanonymity=Column(String(300))#匿名方法国家=Column(String(300))#Countryxtype=Column(String(300))#Protocolzhuang_tai_ma=Column(String(300))#状态码ruku_riqi=Column(DATETIME())#存储日期ce_shi=Column(String(300))#测试状态seshi_ri_qi=Column(DATETIME())#测试日期shi_xiao_riqi=Column(DATETIME())#到期日期definit_db():Base.metadata.create_all(ENGINE)#创建指定表def到数据库drop_db():Base.metadata.drop_all(ENGINE)#从数据库中删除指定表defsession():cls=sessionmaker(bind=ENGINE)#创建sessionmaker类,操作表returncls()#drop_db()#删除表#init_db()