小项目-数据爬取篇:准备工作 代理ip爬取(分布式,多线程)

普通方式爬取

环境: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

版权所有,未经允许,不得转载哦!!!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值