普通方式爬取
环境:win10 x64,python 3.61
代理网站比较多,有免费的有收费的,我们爬取的数据并不多,用免费的就好,免费代理有个致命缺点就是少数可用,所以我们爬取下来以后最好还要验证一下,验证的逻辑就是访问正常网站,返回状态200的保留,否者删除就好。
由于常用的ip代理网站都爬过,效果都不好,这回再换一个:66代理试试
代理ip的网站爬取都很简单
全部在tr标签里,直接上代码,唯一要注意一下编码问题:
url ='http://www.66ip.cn/1.html'
response = requests.get(url,headers=headers)
soup = BeautifulSoup(response.content.decode("gbk"),"lxml")
trs= soup.find("div",class_="containerbox boxindex").find_all("tr")
for tr in trs[1:]:
ip = tr.find_all("td")[0].get_text()
port = tr.find_all("td")[1].get_text()
proxy = "http://"+ip+":"+port
print(proxy)
看看效果:
成了!
用for循环写个翻页就可以大量爬取了:
第一页
http://www.66ip.cn/1.html
第二页
http://www.66ip.cn/2.html
规律显而易见,于是有:
for i in range(1,101):
url= 'http://www.66ip.cn/'+str(i)+'.html'
别忘了加上,时间间隔,否者ip有可能被锁:
time.sleep(random.randint(3,4))
这样代理ip就获取到了,然而这只完成了一半都不到,因为我们还要验证是否可用,选个网站进行验证,返回200状态着可用,可用ip保存下来:
http://www.runoob.com/python3/python3-tutorial.html
我是就用这个试的
这里说一下requests包的proxies的格式是:
{"http":"http://186.88.74.35:8080"}
因此,只要:
proxies = {"http":proxy}
test_url = "http://www.runoob.com/python3/python3-tutorial.html"
response = requests.get(test_url,headers=headers,proxies=proxies,timeout=3)
if response.status_code ==200:
则为可用ip:
with open("ip_pool.txt","a",encoding="utf-8") as f:
f.write(proxy+"\n")
f.close()
保存起来即可,完整代码在这:。
分布式+多线程爬取
什么?验证的太慢?不要急,我们来开大招!!!
何为多线程,何为分布式~
我也解释不太清,我们问下度娘哈:
多线程,似乎就是同时可以执行多个任务:
分布式,知乎上这个帅小伙解释的很清楚:
那我们要做什么呢?
写两个爬虫一个用来爬ip,一个用来验证ip,同时进行,此为分布式
验证的过程添加线程来提高验证效率,此为多线程
了解要干什么了,开搞
这回我们需要一个数据库来存取ip:redis,我是下载地址,安装方法自行百度。
发现66代理成功率更低,这回我们会换成快代理试试,看他的名字应该挺快,我就信他一次
python 要连 redis,还要
pip install redis
我们先来完成下载ip的部分:
连接redis
r = redis.from_url("redis://:你的密码@localhost:6379/0")
or
r = redis.Redis(host='localhost', port=6379, db=0,password=你的密码)
redis 在python上的使用,详细看这。
我简单讲一下今天要用到的
lpush(name,values):在name对应的list中添加元素,每个新的元素都添加到列表的最左边
rpop(name):在name对应的列表的右侧获取第一个元素并在列表中移除,返回值则是第一个元素
hset(name, key, value):name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
hget(name,key):在name对应的hash中获取根据key获取value
hdel(name,*keys):将name对应的hash中指定key的键值对删除
hkeys(name):获取name对应的hash中所有的key的值
hash的好处是一个key对应一个value,可以方便的根据key找到value
获取ip 部分
同样是在tr里,跟66获取基本相同,代码如下:
url= 'http://www.kuaidaili.com/free/inha/'+str(i)+'/'
response = requests.get(url,headers=headers1)
soup = BeautifulSoup(response.text,"lxml")
trs= soup.find("table",class_="table table-bordered table-striped").find_all("tr")
for tr in trs[1:]:
ip = tr.find_all("td")[0].get_text()
port = tr.find_all("td")[1].get_text()
proxy = "http://"+ip+":"+port
# 存入redis name为kuai_ip的列表中,选择左边插入
r.lpush("kuai_ip",proxy)
time.sleep(random.randint(3, 4))
加上翻页后获取ip的部分就搞定了
然后是测试ip部分,这回我们选择百度主页,承载量大
直接上代码了:
def test_ip(ip):
headers = {
'Referer': 'http://www.baudi.com/',
'User-Agent': random.choice(USA)
}
try:
proxies = {"http":ip}
test_url = "http://www.baidu.com/"
# timeout 为访问超时设置,我设置为3秒,根据自己喜好更改
response = requests.get(test_url, headers=headers, proxies=proxies, timeout=3)
status = response.status_code
if status == 200:
print("—————biubiu 连接成功:{}可用——————".format(ip))
key = ip.split("/")[-1]
# times 用来记录改ip成功获取网页次数,
r.hset("hash_kuai", key, {"ip": ip, "times": 1})
# 有时网站会应为对user-agent做限制,导致403错误,并不代表ip不可用
elif status ==403:
print("##########dudu 连接403:{}回炉重造############".format(ip))
r.lpush("kuai_ips", ip)
else :
print("***********dudu 连接失败:{}果断弃了************".format(ip))
except Exception as e:
print("**********dudu 连接失败:{}果断弃了****************".format(ip))
pass
if __name__ == '__main__':
r = redis.from_url("redis://:密码@localhost:6379/0", decode_responses=True)
while True:
# 左边插入,右边取出同时进行
ip = r.rpop("kuai_ips")
# 每隔0.3秒增加一个线程,加快验证,时间长短可以根据自己喜好调整
t1 =threading.Thread(target=test_ip,args=[ip])
t1.start()
time.sleep(0.3)
当然如果一直用一个网站试的话,可能会受到一些限制,于是
url_list =["http://www.baidu.com/","https://v.qq.com/","https://www.tmall.com/","http://www.sina.com.cn/"]
test_url = random.choice(url_list)
这样就解决了,这就是这回的全部内容,代码已上传gayhub。
下一章可就要用得到的代理ip搞事情了,爬取智联招聘工作数据。
曾怯怯的以为自己只是漂泊的种子,总有地方让我滋长声息,可奈何我只是一粒尘埃,漂泊却是最好的归属。
——by 泛泛之素
2017.12.29
版权所有,未经允许,不得转载哦!!!