广告
返回顶部
首页 > 资讯 > 后端开发 > Python >【Python3爬虫】教你怎么利用免费代
  • 825
分享到

【Python3爬虫】教你怎么利用免费代

爬虫教你 2023-01-30 23:01:55 825人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

有时候你的爬虫刚开始的时候可以正常运行,能够正常的爬取数据,但是过了一会,却出现了一个“403 Forbidden",或者是”您的IP访问频率太高“这样的提示,这就意味着你的IP被ban了,好一点的情况是过一段时间你就能继续爬取了,坏一

有时候你的爬虫刚开始的时候可以正常运行,能够正常的爬取数据,但是过了一会,却出现了一个“403 Forbidden",或者是”您的IP访问频率太高“这样的提示,这就意味着你的IP被ban了,好一点的情况是过一段时间你就能继续爬取了,坏一点的情况就是你的IP已经进入别人的黑名单了,然后你的爬虫就GG了。怎么办呢?我们可以通过设置代理来解决,付费代理的效果自然不必多说,但是对于学习阶段的人来说,我觉得爬取网上的免费代理来用是一个更好的选择,而这一篇博客就将教你怎么利用免费代理搭建属于你自己的代理池。

 

要搭建一个代理池,需要三个模块:存储模块、爬取模块和测试模块。

存储模块:负责存储我们爬取下来的代理,首先我们需要保证这些代理不能有重复的,然后我们还要对代理是否可用进行标记,这里可以使用Redis数据库的SortedSet(有序集合)进行存储。

爬取模块:负责对一些提供免费代理的网站进行爬取,代理的形式是IP+端口,爬取下来之后保存到数据库里。

测试模块:负责对代理池中的代理的可用性进行测试,由于测试出错不一定就表明代理不可用,可能是因为网络问题或者请求超时等等,所以我们可以设置一个分数标识,100分标识可用,分数越低标识可用性越低,当分数低于一个阈值之后,就从代理池中移除。

 

1、存储模块

这里使用的是Redis的有序集合。Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员,不同的是每个元素都会关联一个double类型的分数,Redis正是通过分数来为集合中的成员进行从小到大的排序。这样我们保存到数据库中的元素就是一个代理和一个分数,比如112.17.65.133:8060和100,这就表示112.17.65.133:8060这个代理是可用的。

对于新添加到数据库中的代理,设置的初始分数为10,添加之后会进行一次测试,如果可用就把分数改为100表明可用,如果测试的结果是不可用就把分数减1,当分数减到0后就从代理池中移除。这么做的意义在于一次测试不可用并不能代表这个代理完全不可用,有可能在之后的某次测试中是可用的,这样我们就减小了将一个原本可用的代理从代理池中移除出去的概率。

当我们想要从代理池中获取一个代理的时候,优先从分数为100的代理中随机获取,如果一个100分的代理都没有,则对所有代理进行排序,然后随机获取一个代理。由于我们使用的是随机获取,这样就能保证代理池中的所有代理都有被获取的可能性。

现在我们需要定义一个类来实现这个有序集合,还需要设置一些方法来实现添加代理、修改分数、获取代理等功能。具体代码如下:

  1 """
  2 Version: python3.5
  3 Author: ONIOn
  4 Site: Http://www.cnblogs.com/TM0831/
  5 Time: 2019/2/12 14:54
  6 """
  7 import redis
  8 import random
  9 
 10 MAX_SCORE = 100  # 最高分
 11 MIN_SCORE = 0  # 最低分
 12 INITIAL_SCORE = 10  # 初始分数
 13 REDIS_HOST = "localhost"
 14 REDIS_PORT = 6379
 15 
 16 
 17 class RedisClient:
 18     def __init__(self):
 19         self.db = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0)
 20         self.key = "proxies"
 21 
 22     def add(self, proxy, score=INITIAL_SCORE):
 23         """
 24         将代理添加到代理池中
 25         :param proxy: 代理
 26         :param score: 分数
 27         :return:
 28         """
 29         if not self.is_exist(proxy):
 30             self.db.zadd(self.key, proxy, score)
 31 
 32     def is_exist(self, proxy):
 33         """
 34         判断代理池中是否存在该代理
 35         :param proxy: 代理
 36         :return: True or False
 37         """
 38         if self.db.zscore(self.key, proxy):
 39             return True
 40         else:
 41             return False
 42 
 43     def random(self):
 44         """
 45         获取有效代理,先获取最高分代理,如果不存在,则按分数排名然后随机获取
 46         :return: 代理
 47         """
 48         result = self.db.zrangebyscore(self.key, MAX_SCORE, MAX_SCORE)
 49         if len(result):
 50             return random.choice(result)
 51         else:
 52             result = self.db.zrangebyscore(self.key, MIN_SCORE, MAX_SCORE)
 53             if len(result):
 54                 return random.choice(result)
 55             else:
 56                 print("代理池已空!")
 57 
 58     def decrease(self, proxy):
 59         """
 60         代理分数减1分,若小于最低分,则从代理池中移除
 61         :param proxy:
 62         :return:
 63         """
 64         if self.is_exist(proxy):
 65             score = self.db.zscore(self.key, proxy)
 66             if score > MIN_SCORE:
 67                 score -= 1
 68                 self.db.zadd(self.key, proxy, score)
 69             else:
 70                 self.delete(proxy)
 71 
 72     def max(self, proxy):
 73         """
 74         将代理分数设置为最高分
 75         :param proxy: 代理
 76         :return:
 77         """
 78         if self.is_exist(proxy):
 79             self.db.zadd(self.key, proxy, MAX_SCORE)
 80 
 81     def delete(self, proxy):
 82         """
 83         从代理池中移除该代理
 84         :param proxy: 代理
 85         :return:
 86         """
 87         if self.is_exist(proxy):
 88             self.db.zrem(self.key, proxy)
 89 
 90     def all(self):
 91         """
 92         获取代理池中的所有代理
 93         :return:
 94         """
 95         if self.count():
 96             return self.db.zrange(self.key, MIN_SCORE, MAX_SCORE)
 97 
 98     def count(self):
 99         """
100         获取代理池中代理数量
101         :return:
102         """
103         return self.db.zcard(self.key)

2、爬取模块

爬取模块比较简单,就是定义一个Crawler类来对一些提供免费代理的网站进行爬取。具体代码如下:

 1 """
 2 Version: python3.5
 3 Author: OniOn
 4 Site: http://www.cnblogs.com/TM0831/
 5 Time: 2019/2/12 15:07
 6 """
 7 import requests
 8 from lxml import etree
 9 from fake_useragent import UserAgent
10 
11 
12 # 设置元类
13 class CrawlMetaClass(type):
14     def __new__(cls, name, bases, attrs):
15         attrs['__CrawlFuncCount__'] = 0
16         attrs['__CrawlFunc__'] = []
17         for k, v in attrs.items():
18             if 'crawl_' in k:
19                 attrs['__CrawlFunc__'].append(k)
20                 attrs['__CrawlFuncCount__'] += 1
21         # attrs['__CrawlFuncCount__'] = count
22         return type.__new__(cls, name, bases, attrs)
23 
24 
25 class Crawler(object, metaclass=CrawlMetaClass):
26     def __init__(self):
27         self.proxies = []  # 代理列表
28         ua = UserAgent()  # 使用随机UA
29         self.headers = {
30             "UserAgent": ua.random
31         }
32 
33     def get_proxies(self, callback):
34         """
35         运行各个代理爬虫
36         :param callback: crawl函数名称
37         :return:
38         """
39         for proxy in eval("self.{}()".fORMat(callback)):
40             print("成功获取代理:", proxy)
41             self.proxies.append(proxy)
42         return self.proxies
43 
44     def crawl_kdd(self):
45         """
46         快代理爬虫
47         :return:
48         """
49         urls = ["https://www.kuaidaili.com/free/inha/{}/".format(i) for i in range(1, 4)]
50         for url in urls:
51             res = requests.get(url, headers=self.headers)
52             try:
53                 et = etree.html(res.text)
54                 ip_list = et.xpath('//*[@data-title="IP"]/text()')
55                 port_list = et.xpath('//*[@data-title="PORT"]/text()')
56                 for ip, port in zip(ip_list, port_list):
57                     yield ip + ":" + port
58             except Exception as e:
59                 print(e)
60 
61     def crawl_89ip(self):
62         """
63         89IP爬虫
64         :return:
65         """
66         urls = ["http://www.89ip.cn/index_{}.html".format(i) for i in range(1, 4)]
67         for url in urls:
68             res = requests.get(url, headers=self.headers)
69             try:
70                 et = etree.HTML(res.text)
71                 ip_list = et.xpath('//*[@class="layui-table"]/tbody/tr/td[1]/text()')
72                 port_list = et.xpath('//*[@class="layui-table"]/tbody/tr/td[2]/text()')
73                 ip_list = [i.strip() for i in ip_list]
74                 port_list = [i.strip() for i in port_list]
75                 for ip, port in zip(ip_list, port_list):
76                     yield ip + ":" + port
77             except Exception as e:
78                 print(e)
79 
80     def crawl_xc(self):
81         """
82         西刺代理爬虫
83         :return:
84         """
85         url = "https://www.xicidaili.com/?t=253"
86         res = requests.get(url, headers=self.headers)
87         try:
88             et = etree.HTML(res.text)
89             ip_list = et.xpath('//*[@id="ip_list"]/tr[3]/td[2]/text()')
90             port_list = et.xpath('//*[@id="ip_list"]/tr[3]/td[3]/text()')
91             for ip, port in zip(ip_list, port_list):
92                 yield ip + ":" + port
93         except Exception as e:
94             print(e)

可以看到几个爬虫的方法名称都是以crawl开头的,主要是为了方便,如果要添加新的爬虫就只用添加crawl开头的方法即可。

这里我写了爬取快代理、89IP代理和西刺代理的爬虫,都是用xpath进行解析,也都定义了一个生成器,然后用yield返回爬取到的代理。然后定义了一个get_proxies()方法,将所有以crawl开头的方法都调用一遍,获取每个方法返回的结果并生成一个代理列表,最后返回这个代理列表。那么如何获取crawl开头的方法呢?这里借用了元类来实现。首先定义一个类CrawlMetaClass,然后实现了__new__()方法,这个方法的第四个参数attrs里包含了类的一些属性,所以我们可以遍历attrs中包含的信息,就像遍历一个字典一样,如果方法名以crawl开头,就将其添加到__CrawlFunc__中,这样我们就能获取crawl开头的方法了。

我们已经定义好了爬取的方法了,但是还需要定义一个类来执行这些方法,这里可以定义一个GetProxy类来实现爬取代理并保存到代理池中,具体代码如下:

 1 """
 2 Version: Python3.5
 3 Author: OniOn
 4 Site: http://www.cnblogs.com/TM0831/
 5 Time: 2019/2/14 12:19
 6 """
 7 from ProxyPool.crawl import Crawler
 8 from ProxyPool.pool import RedisClient
 9 
10 
11 class GetProxy:
12     def __init__(self):
13         self.crawler = Crawler()
14         self.redis = RedisClient()
15 
16     def get_proxy(self):
17         """
18         运行爬虫爬取代理
19         :return:
20         """
21         print("[INFO]Crawl Start...")
22         count = 0
23         for callback_label in range(self.crawler.__CrawlFuncCount__):
24             callback = self.crawler.__CrawlFunc__[callback_label]
25             # 获取代理
26             proxies = self.crawler.get_proxies(callback)
27             for proxy in proxies:
28                 self.redis.add(proxy)
29             count += len(proxies)
30         print("此次爬取的代理数量为:{}".format(count))
31         print("[INFO]Crawl End...\n\n")

3、测试模块

我们已经将代理成功爬取下来并保存到代理池中了,但是我们还需要对代理的可用性进行测试。测试的方法就是使用requests库设置代理并发送请求,如果请求成功并且返回的状态码是200的话,就表明这个代理是可用的,然后我们就要将该代理的分数设置为100,反之如果出现请求失败、请求超时或者返回的状态码不是200的话, 就要将该代理的分数减1,如果分数等于0了,就要从代理池中移除。

这里可以定义一个TestProxy类来实现,具体代码如下:

 1 """
 2 Version: Python3.5
 3 Author: OniOn
 4 Site: http://www.cnblogs.com/TM0831/
 5 Time: 2019/2/14 14:24
 6 """
 7 import time
 8 import random
 9 import requests
10 from fake_useragent import UserAgent
11 from ProxyPool.crawl import Crawler
12 from ProxyPool.pool import RedisClient
13 
14 
15 class TestProxy:
16     def __init__(self):
17         self.crawler = Crawler()
18         self.redis = RedisClient()
19         ua = UserAgent()  # 使用随机UA
20         self.headers = {
21             "UserAgent": ua.random
22         }
23 
24     def test(self):
25         """
26         测试函数,测试代理池中的代理
27         :return:
28         """
29         proxy_list = self.redis.all()
30         proxy_list = [i.decode('utf-8') for i in proxy_list]  # 字节型转字符串型
31 
32         print("[INFO]Test Start...")
33         for proxy in proxy_list:
34             self.request(proxy)
35         print("[INFO]Test End...\n\n")
36 
37     def request(self, proxy):
38         """
39         测试请求函数
40         :param proxy:
41         :return:
42         """
43         print("当前测试代理:{}   该代理分数为:{}".format(proxy, self.redis.db.zscore(self.redis.key, proxy)))
44         time.sleep(random.randint(1, 4))
45         try:
46             url = "https://www.baidu.com/"
47             proxies = {
48                 "https": "https://" + proxy
49             }
50             res = requests.get(url, headers=self.headers, proxies=proxies, timeout=5)
51 
52             if res.status_code == 200:
53                 print("代理可用,分数设置为100")
54                 self.redis.max(proxy)
55             else:
56                 print("错误的请求状态码,分数减1")
57                 self.redis.decrease(proxy)
58         except:
59             print("代理请求失败,分数减1")
60             self.redis.decrease(proxy)

 

这里我定义了一个Main类来实现,过程为先爬取代理,然后对代理池中的代理进行测试,最后从代理池中获取一个可用代理。具体代码如下:

 1 """
 2 Version: Python3.5
 3 Author: OniOn
 4 Site: http://www.cnblogs.com/TM0831/
 5 Time: 2019/2/14 14:26
 6 """
 7 from ProxyPool.pool import RedisClient
 8 from ProxyPool.get import GetProxy
 9 from ProxyPool.test import TestProxy
10 
11 
12 class Main:
13     def __init__(self):
14         self.gp = GetProxy()
15         self.tp = TestProxy()
16         self.db = RedisClient()
17 
18     def run(self):
19         """
20         运行的主函数,先爬取代理,然后测试,最后获取一个有效代理
21         :return:
22         """
23         self.gp.get_proxy()
24         self.tp.test()
25         proxy = self.db.random()
26         proxy = proxy.decode('utf-8')
27         print("从代理池中取出的代理为:{}".format(proxy))
28 
29 
30 if __name__ == '__main__':
31     m = Main()
32     m.run()

运行结果截图如下:

爬取完毕,开始测试

测试完毕,获取代理

 

完整代码已上传到GitHub

--结束END--

本文标题: 【Python3爬虫】教你怎么利用免费代

本文链接: https://www.lsjlt.com/news/181134.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 【Python3爬虫】教你怎么利用免费代
    有时候你的爬虫刚开始的时候可以正常运行,能够正常的爬取数据,但是过了一会,却出现了一个“403 Forbidden",或者是”您的IP访问频率太高“这样的提示,这就意味着你的IP被ban了,好一点的情况是过一段时间你就能继续爬取了,坏一...
    99+
    2023-01-30
    爬虫 教你
  • 教你如何利用python3爬虫爬取漫画岛-非人哉漫画
        最近学了一点点python爬虫的知识,面向百度编程爬了一本小说之后感觉有点不满足,于是突发奇想尝试爬一本漫画下来看看。 一、效果展示   首先是我们想要爬取的漫画网页:htt...
    99+
    2022-11-12
  • 怎么利用HTTP代理避免爬虫被封
    本篇内容介绍了“怎么利用HTTP代理避免爬虫被封”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!现在我们可以充分发挥爬虫技术,大量收集数据。爬...
    99+
    2023-06-20
  • 爬虫使用免费http代理需要注意什么
    本篇内容介绍了“爬虫使用免费http代理需要注意什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!很多地方都能用网络交换ip,很多时候ip出...
    99+
    2023-06-20
  • 怎么使用爬虫代理ip避免被封
    这篇文章主要为大家展示了“怎么使用爬虫代理ip避免被封”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“怎么使用爬虫代理ip避免被封”这篇文章吧。1、正确处理cookie,可以避免很多收集问题,建议...
    99+
    2023-06-15
  • python爬虫怎么利用requests制作代理池s
    本篇内容介绍了“python爬虫怎么利用requests制作代理池s”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  爬取代理然后验证代理,...
    99+
    2023-06-02
  • 【Python合集系列】爬虫有什么用,网友纷纷给出自己的答案,王老师,我..我想学那个..爬虫。可以嘛?“(代码免费分享)
    导语 Hello,大家好呀!我是木木子吖~ 一个集美貌幽默风趣善良可爱并努力码代码的程序媛一枚。 听说关注我的人会一夜暴富发大财哦~ (哇哇哇 这真的爱😍😍)  生活中总有些东西值得爬一爬 爬虫可以从网站...
    99+
    2023-09-18
    python 爬虫 爬虫合集实战
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作