代码目录结构
https://github.com/Python3WebSpider/ProxyPool/
#文件目录组织结构
.
├── deployment.yml
├── docker-compose.yml
├── Dockerfile
├── error.log
├── examples
│ ├── __init__.py
│ └── usage.py
├── ingress.yml
├── LICENSE
├── proxypool
│ ├── crawlers
│ │ ├── base.py
│ │ ├── __init__.py
│ │ ├── private
│ │ │ ├── __init__.py
│ │ │ └── __pycache__
│ │ │ └── __init__.cpython-36.pyc
│ │ ├── public
│ │ │ ├── daili66.py
│ │ │ ├── data5u.py
│ │ │ ├── __init__.py
│ │ │ ├── ip3366.py
│ │ │ ├── iphai.py
│ │ │ ├── kuaidaili.py
│ │ │ ├── __pycache__
│ │ │ │ ├── daili66.cpython-36.pyc
│ │ │ │ ├── data5u.cpython-36.pyc
│ │ │ │ ├── __init__.cpython-36.pyc
│ │ │ │ ├── ip3366.cpython-36.pyc
│ │ │ │ ├── iphai.cpython-36.pyc
│ │ │ │ ├── kuaidaili.cpython-36.pyc
│ │ │ │ ├── xicidaili.cpython-36.pyc
│ │ │ │ ├── xiladaili.cpython-36.pyc
│ │ │ │ └── zhandaye.cpython-36.pyc
│ │ │ ├── xicidaili.py
│ │ │ ├── xiladaili.py
│ │ │ └── zhandaye.py
│ │ └── __pycache__
│ │ ├── base.cpython-36.pyc
│ │ └── __init__.cpython-36.pyc
│ ├── exceptions
│ │ ├── empty.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ ├── empty.cpython-36.pyc
│ │ └── __init__.cpython-36.pyc
│ ├── __init__.py
│ ├── processors
│ │ ├── getter.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── getter.cpython-36.pyc
│ │ │ ├── __init__.cpython-36.pyc
│ │ │ ├── server.cpython-36.pyc
│ │ │ └── tester.cpython-36.pyc
│ │ ├── server.py
│ │ └── tester.py
│ ├── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ ├── scheduler.cpython-36.pyc
│ │ └── setting.cpython-36.pyc
│ ├── scheduler.py
│ ├── schemas
│ │ ├── __init__.py
│ │ ├── proxy.py
│ │ └── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ └── proxy.cpython-36.pyc
│ ├── setting.py
│ ├── storages
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── __init__.cpython-36.pyc
│ │ │ └── redis.cpython-36.pyc
│ │ └── redis.py
│ └── utils
│ ├── __init__.py
│ ├── parse.py
│ ├── proxy.py
│ └── __pycache__
│ ├── __init__.cpython-36.pyc
│ ├── parse.cpython-36.pyc
│ └── proxy.cpython-36.pyc
├── README.md
├── requirements.txt
├── run.py
├── runtime.log
└── supervisord.conf
19 directories, 69 files
utils
utils 包含两个工具函数
parse.py解析redis的连接字符串,然后返回密码, ip 和port
python3
>>> import re
>>> connection_string = "redis://[redhat]@192.168.0.1:6379"
>>> result = re.match('rediss?://(.*?)@(.*?):(d+)', connection_string)
>>> result.group(2)
'192.168.0.1'
>>> result
<_sre.SRE_Match object; span=(0, 33), match='redis://[redhat]@192.168.0.1:6379'>
>>> result.groups()
('[redhat]', '192.168.0.1', '6379')
>>> result.group(3)
'6379'
>>> result.group(1)
'[redhat]'
>>> result.group(0)
'redis://[redhat]@192.168.0.1:6379'
proxy.py 传入ip和端口,获取一个类,打印该类则输出ip:port
知识点 :https://www.attrs.org/en/stable/examples.html
pip3 install attrs cattrs
装了 attrs 和 cattrs 这两个库,但是实际导入的时候是使用 attr 和 cattr 这两个包,是不带 s 的
使用attrs 后的代码示例:
from attr import attrs, attrib
@attrs
class Color(object):
r = attrib(type=int, default=0)
g = attrib(type=int, default=0)
b = attrib(type=int, default=0)
if __name__ == '__main__':
color = Color(255, 255, 255)
print(color)
##输出结果
Color(r=255, g=255, b=255)
attrs 这个修饰符起了作用,然后根据定义的 attrib 属性自动帮我们实现了 __init__
、__repr__
、__eq__
、__ne__
、__lt__
、__le__
、__gt__
、__ge__
、__hash__
示例:
##attrs 定义后的类
from attr import attrs, attrib
@attrs
class SmartClass(object):
a = attrib()
b = attrib()
##相当于已经实现了这些方法:
class RoughClass(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return "RoughClass(a={}, b={})".format(self.a, self.b)
def __eq__(self, other):
if other.__class__ is self.__class__:
return (self.a, self.b) == (other.a, other.b)
else:
return NotImplemented
def __ne__(self, other):
result = self.__eq__(other)
if result is NotImplemented:
return NotImplemented
else:
return not result
def __lt__(self, other):
if other.__class__ is self.__class__:
return (self.a, self.b) < (other.a, other.b)
else:
return NotImplemented
def __le__(self, other):
if other.__class__ is self.__class__:
return (self.a, self.b) <= (other.a, other.b)
else:
return NotImplemented
def __gt__(self, other):
if other.__class__ is self.__class__:
return (self.a, self.b) > (other.a, other.b)
else:
return NotImplemented
def __ge__(self, other):
if other.__class__ is self.__class__:
return (self.a, self.b) >= (other.a, other.b)
else:
return NotImplemented
def __hash__(self):
return hash((self.__class__, self.a, self.b))
参考:
https://cuiqingcai.com/6552.html
storages
此模块主要初始化redis连接并实现存储,随机获取,降级分数, ip数量,判断指定ip是否存在
知识点:
pyredis
注释
def random(self) -> Proxy:
声明函数后那个箭头:"->" 是返回值的注释,-> Proxy 意思即是提醒函数使用者返回值会是一个Proxy型
>>> def f(ham: "传一个字符串", eggs: str = 'eggs') -> str :
... print("Annotations:", f.__annotations__)
... print("Arguments:", ham, eggs)
... return ham + ' and ' + eggs
...
>>>
>>>
>>>
>>> f("test", 123)
Annotations: {'eggs': <class 'str'>, 'ham': '传一个字符串', 'return': <class 'str'>}
Arguments: test 123
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in f
TypeError: Can't convert 'int' object to str implicitly
>>> f("test", "tt")
Annotations: {'eggs': <class 'str'>, 'ham': '传一个字符串', 'return': <class 'str'>}
Arguments: test tt
'test and tt'
##.__annotations__是函数的参数注释和返回值注释
##"->" 是返回值的注释,-> str 意思即是提醒函数使用者返回值会是一个str型
setting
配置代码需要的环境变量,日志配置
processor
模块内包含代理ip 获取器,可用代理api server, 代理ip 可用测试器
Getter
初始化redis 连接,获取抓取函数, log catch
loguru 貌似在setting里设置一次就行,项目根目录下, 整个项目会生效???
不了解,待测试, 貌似有全局变量,可以自动的联系起来
调用crawlers内的各个网站的特别的类获取代理
server
利用flask 提供API 获取分数最高的代理
tester
使用异步aiohttp 不断测试代理的可用性,不断调整代理的分数
知识点
argparse 参数添加
multiprocessing
pyredis
loguru
retrying
pkgutil
inspect