上回说到,突破反爬虫限制的方法之一就是多用几个代理IP,但前提是我们得拥有有效的代理IP,下面我们来介绍抓取代理IP并多线程快速验证其有效性的过程。

一、抓取代理IP

提供免费代理IP的网站还挺多的,我在‘西刺代理’上一阵猛抓后自己的IP就被其屏蔽了。只好换‘IP巴士’并乖乖的减缓抓取速度了。贴上抓取代码

import urllib.request
import urllib
import re
import time
import random
#抓取代理IP
ip_totle=[] #所有页面的内容列表
for page in range(2,6):
url='http://ip84.com/dlgn/'+str(page)
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64)"}
request=urllib.request.Request(url=url,headers=headers)
response=urllib.request.urlopen(request)
content=response.read().decode('utf-8')
print('get page',page)
pattern=re.compile('<td>(\d.*?)</td>') #截取<td>与</td>之间第一个数为数字的内容
ip_page=re.findall(pattern,str(content))
ip_totle.extend(ip_page)
time.sleep(random.choice(range(1,3)))
#打印抓取内容
print('代理IP地址 ','\t','端口','\t','速度','\t','验证时间')
for i in range(0,len(ip_totle),4):
print(ip_totle[i],' ','\t',ip_totle[i+1],'\t',ip_totle[i+2],'\t',ip_totle[i+3])

复制以上代码即可抓取IP巴士上的大陆高匿代理IP了,其他地区或类型的可自行改URL,可能是网站内容在实时更新的原因,若从第一页开始抓取不怎么稳定,所以我从第二页开始抓取,打印部分结果如下

二、验证代理IP的有效性

由于所处的网络可能连不上此代理或该代理连不上目标网址等原因,我们抓取的代理有可能是无效的,我们有必要验证所抓取代理IP的有效性。在urllib.request包中的ProxyHandler类可以设置代理访问网页,代码如下

import urllib.request
url = "http://quote.stockstar.com/stock" #打算抓取内容的网页
proxy_ip={'http': '27.17.32.142:80'} #想验证的代理IP
proxy_support = urllib.request.ProxyHandler(proxy_ip)
opener = urllib.request.build_opener(proxy_support)
opener.addheaders=[("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64)")]
urllib.request.install_opener(opener)
print(urllib.request.urlopen(url).read())

若IP是有效的,则可打印出网页源码,否则会出现错误。所以我们可以通过以上代码对所抓取的代理IP逐个进行验证。

三、多线程快速验证

按顺序逐个验证代理IP的有效性速度比较慢,python中有多线程模块,多线程类似于同时执行多个不同程序,使用多线程可以把占据长时间的程序中的任务放到后台去处理,在一些需要等待的任务实现上线程就比较有用了。

Python通过两个标准库thread和threading提供对线程的支持。thread模块提供了低级别的、原始的线程以及一个简单的锁。threading 是我们常用的用于python 多线程的模块,其功能更加丰富。threading 模块中提供了一个Thread 类,这个类可以实例化一个对象,每个对象代表一个线程。下面我们介绍下本文使用threading模块中的类。

我们先介绍线程锁,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,比如我们的一个print语句只打印出一半的字符,这个线程就被暂停,执行另一个去了,所以我们看到的结果会很乱,这种现象叫做“线程不安全”。Threading模块为我们提供了Threading.Lock类,我们创建一个该类对象,在线程函数执行前,“抢占”该锁,执行完成后,“释放”该锁,则我们确保了每次只有一个线程占有该锁。这时候对一个公共的对象进行操作,则不会发生线程不安全的现象了。我们先建立了一个threading.Lock类对象lock,使用lock.acquire()获得了这个锁。此时,其他的线程就无法再获得该锁了,他们就会阻塞在“if lock.acquire()”这里,直到锁被另一个线程释放:lock.release()。

然后我们来介绍threading模块中的Thread 类。class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *,daemon=None), 这个构造函数通常会用一些关键字参数,下面我们了解下这些关键字:
       group :这个变量作为保留变量,是为了以后扩展用的,暂时可以不用考虑。
       target: 是通过run()方法调用的可调用对象。默认为无,这意味着什么都不做。
       name:线程的名字。默认情况下,一个唯一的名称是”thread-n”的形式,其中n是一个小的十进制数。
       args:元组参数,为target所调用的。
       kwargs:关键字参数的字典,为target所调用的。
       daemon: 设置daemon是否daemon 如果没有显示设置,daemon的属性时从当前线程继承。
       如果子类重写此构造函数,它必须确保在做别的事情之前调用基类的构造函数thread.__init__()。本文所用到Thread 类的方法有:      
       start(self)       
       开始线程的运行,每个线程对象只有调用最多一次。它将调用被调用对象的run()方法,并控制各个对象独立运行。也就是说被调用的对象必要要有run() 方法,在使用Thread 类来实例化对象的时候,因为Thread 中已经有了run() 方法了,所以可以不用理。但是,在基础Thread 创建子类的时候,一般我们要重写子类的run()方法。
       join(self, timeout=None)
       阻塞主线程,直到调用该方法的子线程运行完毕或者超时。timeout 表示超时时间,可以是一个数,例如整数,小数,分数,表示超时的时间,单位是秒。返回值为 None,可以在 join 超时之后调用 isAlive 确认线程是否结束。如果线程还活动,说明 join 触发了超时,此时你可以继续调用 join 或者做其他处理。当 timeout 没有给或者为 None 的时候,将阻塞直到调用此方法的子线程结束。一个线程可以调用多次 join 方法。

多线程验证的主要程序如下

#多线程验证
threads=[]
for i in range(len(proxys)):
thread=threading.Thread(target=test,args=[i])
threads.append(thread)
thread.start()
#阻塞主进程,等待所有子线程结束
for thread in threads:
thread.join()

一开始我我令元组参数args=(i),结果报‘test() argument after * must be an iterable, not int’的错误,误打误撞把小括号改为中括号后就有用了,暂时不解中其缘由,望知情者能告知。程序部分运行结果如下

亲测多线程验证比单线程验证快了好几倍,所以以后在爬取网页量比较大时就可以先用此程序抓一些有效的代理IP,这样就可以解决IP被屏蔽的问题啦。python3抓取代理IP并用多线程快速验证的完整代码如下

import urllib.request
import urllib
import re
import time
import random
import socket
import threading
#抓取代理IP
ip_totle=[]
for page in range(2,6):
url='http://ip84.com/dlgn/'+str(page)
#url='http://www.xicidaili.com/nn/'+str(page) #西刺代理
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64)"}
request=urllib.request.Request(url=url,headers=headers)
response=urllib.request.urlopen(request)
content=response.read().decode('utf-8')
print('get page',page)
pattern=re.compile('<td>(\d.*?)</td>') #截取<td>与</td>之间第一个数为数字的内容
ip_page=re.findall(pattern,str(content))
ip_totle.extend(ip_page)
time.sleep(random.choice(range(1,3)))
#打印抓取内容
print('代理IP地址 ','\t','端口','\t','速度','\t','验证时间')
for i in range(0,len(ip_totle),4):
print(ip_totle[i],' ','\t',ip_totle[i+1],'\t',ip_totle[i+2],'\t',ip_totle[i+3])
#整理代理IP格式
proxys = []
for i in range(0,len(ip_totle),4):
proxy_host = ip_totle[i]+':'+ip_totle[i+1]
proxy_temp = {"http":proxy_host}
proxys.append(proxy_temp) proxy_ip=open('proxy_ip.txt','w') #新建一个储存有效IP的文档
lock=threading.Lock() #建立一个锁
#验证代理IP有效性的方法
def test(i):
socket.setdefaulttimeout(5) #设置全局超时时间
url = "http://quote.stockstar.com/stock" #打算爬取的网址
try:
proxy_support = urllib.request.ProxyHandler(proxys[i])
opener = urllib.request.build_opener(proxy_support)
opener.addheaders=[("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64)")]
urllib.request.install_opener(opener)
res = urllib.request.urlopen(url).read()
lock.acquire() #获得锁
print(proxys[i],'is OK')
proxy_ip.write('%s\n' %str(proxys[i])) #写入该代理IP
lock.release() #释放锁
except Exception as e:
lock.acquire()
print(proxys[i],e)
lock.release()
#单线程验证
'''for i in range(len(proxys)):
test(i)'''
#多线程验证
threads=[]
for i in range(len(proxys)):
thread=threading.Thread(target=test,args=[i])
threads.append(thread)
thread.start()
#阻塞主进程,等待所有子线程结束
for thread in threads:
thread.join() proxy_ip.close() #关闭文件

proxy_ip

python爬虫成长之路(二):抓取代理IP并多线程验证的更多相关文章

  1. python爬虫之分析Ajax请求抓取抓取今日头条街拍美图(七)

    python爬虫之分析Ajax请求抓取抓取今日头条街拍美图 一.分析网站 1.进入浏览器,搜索今日头条,在搜索栏搜索街拍,然后选择图集这一栏. 2.按F12打开开发者工具,刷新网页,这时网页回弹到综合 ...

  2. python爬虫成长之路(一):抓取证券之星的股票数据

    获取数据是数据分析中必不可少的一部分,而网络爬虫是是获取数据的一个重要渠道之一.鉴于此,我拾起了Python这把利器,开启了网络爬虫之路. 本篇使用的版本为python3.5,意在抓取证券之星上当天所 ...

  3. python爬虫实战(一)——实时获取代理ip

    在爬虫学习的过程中,维护一个自己的代理池是非常重要的. 详情看代码: 1.运行环境 python3.x,需求库:bs4,requests 2.实时抓取西刺-国内高匿代理中前3页的代理ip(可根据需求自 ...

  4. scrapy爬虫成长日记之将抓取内容写入mysql数据库

    前面小试了一下scrapy抓取博客园的博客(您可在此查看scrapy爬虫成长日记之创建工程-抽取数据-保存为json格式的数据),但是前面抓取的数据时保存为json格式的文本文件中的.这很显然不满足我 ...

  5. Python爬虫实战:使用Selenium抓取QQ空间好友说说

    前面我们接触到的,都是使用requests+BeautifulSoup组合对静态网页进行请求和数据解析,若是JS生成的内容,也介绍了通过寻找API借口来获取数据. 但是有的时候,网页数据由JS生成,A ...

  6. Python爬虫入门教程 45-100 Charles抓取兔儿故事-下载小猪佩奇故事-手机APP爬虫部分

    1. Charles抓取兔儿故事背景介绍 之前已经安装了Charles,接下来我将用两篇博客简单写一下关于Charles的使用,今天抓取一下兔儿故事里面关于小猪佩奇的故事. 爬虫编写起来核心的重点是分 ...

  7. [Python爬虫] 之八:Selenium +phantomjs抓取微博数据

    基本思路:在登录状态下,打开首页,利用高级搜索框输入需要查询的条件,点击搜索链接进行搜索.如果数据有多页,每页数据是20条件,读取页数 然后循环页数,对每页数据进行抓取数据. 在实践过程中发现一个问题 ...

  8. Python爬虫之-动态网页数据抓取

    什么是AJAX: AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML.过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意 ...

  9. Python 爬虫抓取代理IP,并检测联通性

    帮朋友抓了一些代理IP,并根据测试联的通性,放在了不通的文件夹下.特将源码分享 注意: 1,环境Python3.5 2,安装BeautifulSoup4  requests 代码如下: 1 2 3 4 ...

随机推荐

  1. HDU 5944 Fxx and string(暴力/枚举)

    传送门 Fxx and string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Othe ...

  2. CTP程序化系统开发(C++ && PHP)

    2016-12-13 11:03:52 借助CTP的DEMO(上海期货交易公司提供的), 需要自己在 http://www.simnow.com.cn  上注册账号, 再者,需要下载[博易大师]软件, ...

  3. 在windows下使用linux命令,GnuWin32的使用.

    http://sourceforge.net/projects/getgnuwin32 使用过linxu的伙计估计都会喜欢上linux各种各样强大的命令如:grep, sed,awk,diff和pat ...

  4. mysql定时任务

    查看event是否开启: show variables like '%sche%'; 将事件计划开启: set global event_scheduler=1; 关闭事件任务: alter even ...

  5. canvas.drawBitmap()频繁调用导致应用崩溃问题

    因为opengl不熟,要在opengl上面贴文字  时间紧所以用到一个折中的办法  文字转bitmap 因为文字较多,对话形式  还要分行,分段,逻辑处理的比较复杂     运行中会有闪退发生,且不可 ...

  6. xss之渗透测试

    跨站脚本攻击:cross site script execution(通常简写为xss,因css与层叠样式表同名,故改为xss),是指攻击者利用网站程序对用户输入过滤不足,输入可以显示在页面上对其他用 ...

  7. webSphere内存溢出

    有一个做了很长时间的项目,是用websphere做生产环境的,可是一旦加载的项目过多,webSphere就很傲娇的内存溢出,这是一个折腾了公司里某个前辈很久很久的问题,因为是测试版,所以各种官方文档说 ...

  8. Backbone事件模块及其用法

    事件模块Backbone.Events在Backbone中占有十分重要的位置,其他模块Model,Collection,View所有事件模块都依赖它.通过继承Events的方法来实现事件的管理,可以说 ...

  9. R语言作为BI中ETL的工具

    R语言作为BI中ETL的工具,增删改 R语言提供了强大的R_package与各种数据库进行数据交互. 外加其强大数据变换清洗函数,为ETL提供一条方便快捷的道路. RODBC ROracal RMys ...

  10. oracle DDL(数据定义语言)基本语句

    --创建表格 create table  production( ProductIdvarchar2(10), ProductNamevarchar2(20), ProductPricenumber( ...