社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

用Python爬虫抓取免费代理IP

Python中文社区 • 5 年前 • 466 次点击  

--  Illustrations by Ash Thorp & Maciej Kuciara --

作者:HDMI,JUST WANT AND JUST DO

blog地址:zhihu.com/people/hdmi-blog


不知道大家有没有遇到过“访问频率太高”这样的网站提示,我们需要等待一段时间或者输入一个验证码才能解封,但这样的情况之后还是会出现。出现这个现象的原因就是我们所要爬取的网页采取了反爬虫的措施,比如当某个ip单位时间请求网页次数过多时,服务器会拒绝服务,这种情况就是由于访问频率引起的封ip,这种情况靠解封不能很好的解决,所以我们就想到了伪装本机ip去请求网页,也就是我们今天要讲的使用代理ip。

目前网上有许多代理ip,有免费的也有付费的,例如西刺代理等,免费的虽然不用花钱但有效的代理很少且不稳定,付费的可能会好一点,不过今天我只爬取免费的代理并将检测是否可用,将可用ip存入MongoDB,方便下次取出。

运行平台:Windows

Python版本:Python3.6

IDE: Sublime Text

其他:Chrome浏览器

简述流程为:

步骤1:了解requests代理如何使用

步骤2:从代理网页爬取到ip和端口

步骤3:检测爬取到的ip是否可用

步骤4:将爬取的可用代理存入MongoDB

步骤5:从存入可用ip的数据库里随机抽取一个ip,测试成功后返回

对于requests来说,代理的设置比较简单,只需要传入proxies参数即可。

不过需要注意的是,这里我是在本机安装了抓包工具Fiddler,并用它在本地端口8888创建了一个HTTP代理服务(用Chrome插件SwitchyOmega),即代理服务为:127.0.0.1:8888,我们只要设置好这个代理,就可以成功将本机ip切换成代理软件连接的服务器ip了。

  1. import requests

  2. proxy = '127.0.0.1:8888'

  3. proxies = {

  4.    'http':'http://' + proxy,

  5.    'https':'http://' + proxy

  6. }

  7. try:

  8.    response = requests.get('http://httpbin.org/get',proxies=proxies)

  9.    print(response.text)

  10. except requests.exceptions.ConnectionError as e:

  11.    print('Error',e.args)

这里我是用来http://httpbin.org/get作为测试网站,我们访问该网页可以得到请求的有关信息,其中origin字段就是客户端ip,我们可以根据返回的结果判断代理是否成功。返回结果如下:

  1. {

  2.    "args":{},

  3.    "headers":{

  4.        "Accept":"*/*",

  5.        "Accept-Encoding":"gzip, deflate",

  6.        "Connection":"close",

  7.        "Host":"httpbin.org",

  8.        "User-Agent":"python-requests/2.18.4"

  9.    },

  10.    "origin":"xx.xxx.xxx.xxx",

  11.    "url":"http://httpbin.org/get"

  12. }

接下来我们便开始爬取代理IP,首先我们打开Chrome浏览器查看网页,并找到ip和端口元素的信息。

可以看到,代理IP以表格存储ip地址及其相关信息,所以我们用BeautifulSoup提取时很方便便能提取出相关信息,但是我们需要注意的是,爬取的ip很有可能出现重复的现象,尤其是我们同时爬取多个代理网页又存储到同一数组中时,所以我们可以使用集合来去除重复的ip。

将要爬取页数的ip爬取好后存入数组,然后再对其中的ip逐一测试。

这里就用到了上面提到的requests设置代理的方法,我们使用http://httpbin.org/ip作为测试网站,它可以直接返回我们的ip地址,测试通过后再存入MomgoDB数据库。

连接数据库然后指定数据库和集合,再将数据插入就OK了。

最后运行查看一下结果吧

运行了一段时间后,难得看到一连三个测试通过,赶紧截图保存一下,事实上是,毕竟是免费代理,有效的还是很少的,并且存活时间确实很短,不过,爬取的量大,还是能找到可用的,我们只是用作练习的话,还是勉强够用的。现在看看数据库里存储的吧。

因为爬取的页数不多,加上有效ip也少,再加上我没怎么爬,所以现在数据库里的ip并不多,不过也算是将这些ip给存了下来。现在就来看看怎么随机取出来吧。

由于担心放入数据库一段时间后ip会失效,所以取出前我重新进行了一次测试,如果成功再返回ip,不成功的话就直接将其移出数据库。

这样我们需要使用代理的时候,就能通过数据库随时取出来了。

总的代码如下:

  1. import random

  2. import requests

  3. import time

  4. import pymongo

  5. from bs4 import BeautifulSoup

  6. # 爬取代理的URL地址,选择的是西刺代理

  7. url_ip = "http://www.xicidaili.com/nt/"

  8. # 设定等待时间

  9. set_timeout = 5

  10. # 爬取代理的页数,2表示爬取2页的ip地址

  11. num = 2

  12. # 代理的使用次数

  13. count_time = 5

  14. # 构造headers

  15. headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36'}

  16. # 测试ip的URL

  17. url_for_test = 'http://httpbin.org/ip'

  18. def scrawl_xici_ip(num):

  19.    '''

  20.    爬取代理ip地址

  21.    '''  

  22.    ip_list = []

  23.    for num_page in range(1,num):

  24.        url = url_ip + str(num_page)

  25.        response = requests.get(url,headers=headers)

  26.        if response. status_code == 200:

  27.            content = response.text

  28.            soup = BeautifulSoup(content,'lxml')

  29.            trs = soup.find_all('tr')

  30.            for i in range(1,len(trs)):

  31.                tr = trs[i]

  32.                tds = tr.find_all('td')      

  33.                ip_item = tds[1].text + ':' + tds[2].text

  34.                # print(ip_item)

  35.                ip_list.append(ip_item)

  36.                ip_set = set(ip_list) # 去掉可能重复的ip

  37.                ip_list = list(ip_set)

  38.            time.sleep(count_time) # 等待5秒

  39.    return ip_list

  40. def ip_test(url_for_test,ip_info):

  41.    '''

  42.    测试爬取到的ip,测试成功则存入MongoDB

  43.    '''

  44.    for ip_for_test in ip_info:

  45.        # 设置代理

  46.        proxies = {

  47.            'http': 'http://' + ip_for_test,

  48.            'https': 'http://' + ip_for_test,

  49.            }

  50.        print(proxies)

  51.        try:

  52.            response = requests.get(url_for_test,headers=headers,proxies=proxies,timeout=10)

  53.            if response.status_code == 200:

  54.                ip = {'ip':ip_for_test}

  55.                print(response.text)

  56.                print( '测试通过')

  57.                write_to_MongoDB(ip)    

  58.        except Exception as e:

  59.            print(e)

  60.            continue

  61. def write_to_MongoDB(proxies):

  62.    '''

  63.    将测试通过的ip存入MongoDB

  64.    '''

  65.    client = pymongo.MongoClient(host='localhost',port=27017)

  66.    db = client.PROXY

  67.    collection = db.proxies

  68.    result = collection.insert(proxies)

  69.    print(result)

  70.    print( '存储MongoDB成功')

  71. def get_random_ip():

  72.    '''

  73.    随机取出一个ip

  74.    '''

  75.    client = pymongo.MongoClient(host='localhost',port=27017)

  76.    db = client.PROXY

  77.    collection = db.proxies

  78.    items = collection.find()

  79.    length = items.count()

  80.    ind = random.randint(0,length-1)

  81.    useful_proxy = items[ind]['ip'].replace('\n','')

  82.    proxy = {

  83.        'http': 'http://' + useful_proxy,

  84.        'https': 'http://' + useful_proxy,

  85.        }  

  86.    response = requests.get(url_for_test,headers=headers,proxies=proxy,timeout=10)

  87.    if response.status_code == 200:

  88.        return useful_proxy

  89.    else:

  90.        print('此{ip}已失效'.format(useful_proxy))

  91.        collection.remove(useful_proxy)

  92.        print('已经从MongoDB移除')

  93.        get_random_ip()

  94. def main ():

  95.    ip_info = []

  96.    ip_info = scrawl_xici_ip(2)

  97.    sucess_proxy = ip_test(url_for_test,ip_info)

  98.    finally_ip = get_random_ip()

  99.    print('取出的ip为:' + finally_ip)

  100. if __name__ == '__main__':

  101.    main()


Python中文社区
全球Python中文开发者的
精神部落



Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以公安部、工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

▼ 点击下方阅读原文免费成为社区会员


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/AYehk5ieCb
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/14134
 
466 次点击