元类理解与元类编程 《Python3网络爬虫开发》中第九章代理的使用代码Crawler中代码的理解
__new__与__init__的理解
__new__()方法是在创建实例之前被调用的,它的作用是创建一个实例,然后返回该实例对象,它是一个静态方法。
__init__() 当实例被创建完成之后被调用的,然后设置对象属性的一些初始值,是一个实例方法。
也即:__new__先被调用,__init__后被调用,__new__方法中的返回值将实例传递给__init__方法中的第一个参数。然后__init__给这个实例设置一些初始参数。
注意:
1、继承自object的新式类才有__new__
2、__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别
3、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名, cls))__new__出来的实例,或者直接是object的__new__出来的实例
4、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
5、如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是 cls 来保证是当前类实例,如果是其他类的类名;那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__init__函数。
6、在定义子类时没有重新定义__new__()时,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。
10、将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节
11、__new__的一般写法:

class A(object): # -> don t forget the object specified as base def __new__(cls):
print ("A.__new__ called")
return super(A, cls).__new__(cls)
#return super().__new__(cls) # 这样子写也可以,注意要与类的继承简写区别一下,后面的cls不可以省略。
def __init__(self): print("A.__init__ called") A()

通过元类创建类
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import json
import re
from .utils import get_page
from pyquery import PyQuery as pq class ProxyMetaclass(type):
def __new__(cls, name, bases, attrs):
count = 0
attrs['__CrawlFunc__'] = []
for k, v in attrs.items():
if 'crawl_' in k:
attrs['__CrawlFunc__'].append(k)
count += 1
attrs['__CrawlFuncCount__'] = count
return type.__new__(cls, name, bases, attrs) class Crawler(object, metaclass=ProxyMetaclass):
def get_proxies(self, callback):
proxies = []
for proxy in eval("self.{}()".format(callback)):
print('成功获取到代理', proxy)
proxies.append(proxy)
return proxies def crawl_daili66(self, page_count=4):
"""
获取代理66
:param page_count: 页码
:return: 代理
"""
start_url = 'http://www.66ip.cn/{}.html'
urls = [start_url.format(page) for page in range(1, page_count + 1)]
for url in urls:
print('Crawling', url)
html = get_page(url)
if html:
doc = pq(html)
trs = doc('.containerbox table tr:gt(0)').items()
for tr in trs:
ip = tr.find('td:nth-child(1)').text()
port = tr.find('td:nth-child(2)').text()
yield ':'.join([ip, port]) def crawl_kuaidaili(self):
for i in range(1, 4):
start_url = 'http://www.kuaidaili.com/free/inha/{}/'.format(i)
html = get_page(start_url)
if html:
ip_address = re.compile('<td data-title="IP">(.*?)</td>')
re_ip_address = ip_address.findall(html)
port = re.compile('<td data-title="PORT">(.*?)</td>')
re_port = port.findall(html)
for address, port in zip(re_ip_address, re_port):
address_port = address + ':' + port
yield address_port.replace(' ', '') def crawl_xicidaili(self):
for i in range(1, 3):
start_url = 'http://www.xicidaili.com/nn/{}'.format(i)
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Cookie': '_free_proxy_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWRjYzc5MmM1MTBiMDMzYTUzNTZjNzA4NjBhNWRjZjliBjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMUp6S2tXT3g5a0FCT01ndzlmWWZqRVJNek1WanRuUDBCbTJUN21GMTBKd3M9BjsARg%3D%3D--2a69429cb2115c6a0cc9a86e0ebe2800c0d471b3',
'Host': 'www.xicidaili.com',
'Referer': 'http://www.xicidaili.com/nn/3',
'Upgrade-Insecure-Requests': '1',
}
html = get_page(start_url, options=headers)
if html:
find_trs = re.compile('<tr class.*?>(.*?)</tr>', re.S)
trs = find_trs.findall(html)
for tr in trs:
find_ip = re.compile('<td>(\d+\.\d+\.\d+\.\d+)</td>')
re_ip_address = find_ip.findall(tr)
find_port = re.compile('<td>(\d+)</td>')
re_port = find_port.findall(tr)
for address, port in zip(re_ip_address, re_port):
address_port = address + ':' + port
yield address_port.replace(' ', '')
根据网络资料以及个人理解,此段代码用到元类的理解如下:
这里借助了元类来实现所有ProxyMetaclass类中以crawl__开头的方法,具体实现过程如下:
1.首先定义ProxyMetaclass类作为Crawler类的元类,元类中实现__new__()方法,这个方法有固定的几个参数,其中参数含义如下:
name:当前类的名字。
bases:当前类继承的父类,以元组形式提交。
attrs:当前类中所有的属性(包括方法也可以看作特殊的属性)
2.遍历attrs参数即可获取类的所有方法信息,然后判断方法是否以crawl__开头,如果是则将其添加到__CrawlFunc__属性中。这样就将所有的以crawl__开头的方法定义成了一个属性,动态获取到所有以crawl__开头的方法。
过程理解:
当Crawler中启用元类(即实现metaclass=ProxyMetaclass)时,意味着Crawler中的__new__()方法继承自ProxyMetaclass的__new__()方法,该方法的第一个参数cls就代表创建的Crawler类的实例,name为其名字,bases为其父类方法,然后attrs为其所有类方法(其中的key即方法名,value为方法返回值),最后metaclass又通过returnreturn type.__new__(cls, name, bases, attrs)方法,将构建实例的工作又交给了type去完成。只是在传递参数attrs中做了一些改变,于是前面过程2中的方法实现之后使得创建的Crawler类的实例具有了属性__CrawlFunc__ = [crawl_daili66, crawl_kuaidaili, , crawl_xicidaili, crawl_ip3366, crawl_iphai, crawl_data5u] 和属性__CrawlFuncCount__ = 6。实现了动态地设计类。
元类理解与元类编程 《Python3网络爬虫开发》中第九章代理的使用代码Crawler中代码的理解的更多相关文章
- 崔庆才Python3网络爬虫开发实战电子版书籍分享
资料下载地址: 链接:https://pan.baidu.com/s/1WV-_XHZvYIedsC1GJ1hOtw 提取码:4o94 <崔庆才Python3网络爬虫开发实战>高清中文版P ...
- 《Python3 网络爬虫开发实战》开发环境配置过程中踩过的坑
<Python3 网络爬虫开发实战>学习资料:https://www.cnblogs.com/waiwai14/p/11698175.html 如何从墙内下载Android Studio: ...
- 《Python3 网络爬虫开发实战》学习资料
<Python3 网络爬虫开发实战> 学习资料 百度网盘:https://pan.baidu.com/s/1PisddjC9e60TXlCFMgVjrQ
- Python3网络爬虫开发实战PDF高清完整版免费下载|百度云盘
百度云盘:Python3网络爬虫开发实战高清完整版免费下载 提取码:d03u 内容简介 本书介绍了如何利用Python 3开发网络爬虫,书中首先介绍了环境配置和基础知识,然后讨论了urllib.req ...
- 转:【Python3网络爬虫开发实战】 requests基本用法
1. 准备工作 在开始之前,请确保已经正确安装好了requests库.如果没有安装,可以参考1.2.1节安装. 2. 实例引入 urllib库中的urlopen()方法实际上是以GET方式请求网页,而 ...
- [Python3网络爬虫开发实战] 3.1.4-分析Robots协议
利用urllib的robotparser模块,我们可以实现网站Robots协议的分析.本节中,我们来简单了解一下该模块的用法. 1. Robots协议 Robots协议也称作爬虫协议.机器人协议,它的 ...
- [Python3网络爬虫开发实战] 3.2.2-高级用法
在前一节中,我们了解了requests的基本用法,如基本的GET.POST请求以及Response对象.本节中,我们再来了解下requests的一些高级用法,如文件上传.cookie设置.代理设置等. ...
- [Python3网络爬虫开发实战] 3.1.1-发送请求
使用urllib的request模块,我们可以方便地实现请求的发送并得到响应,本节就来看下它的具体用法. 1. urlopen() urllib.request模块提供了最基本的构造HTTP请求的方法 ...
- [Python3网络爬虫开发实战] 1.8.2-Scrapy的安装
Scrapy是一个十分强大的爬虫框架,依赖的库比较多,至少需要依赖的库有Twisted 14.0.lxml 3.4和pyOpenSSL 0.14.在不同的平台环境下,它所依赖的库也各不相同,所以在安装 ...
随机推荐
- SQL行转列,列转行
SQL 行转列,列转行 行列转换在做报表分析时还是经常会遇到的,今天就说一下如何实现行列转换吧. 行列转换就是如下图所示两种展示形式的互相转换 行转列 假如我们有下表: SELECT * FROM s ...
- iOS开发之--为UITextField监听数值变化的三种方法
项目中有个验证码输入直接验证跳转页面,用的RAC来监听textfield的输入值,如下: @weakify(self); [self.codeView.textField.rac_textSignal ...
- 【推荐】全球最全面的Telegram组群频道的集合网站 持续收集中
全球最全面的Telegram组群频道的集合网站 https://www.telegramgroup.org Telegram 组群频道分享 可搜索自己想找的组群频道 从小白到大神,一个 telegra ...
- flink 批量梯度下降算法线性回归参数求解(Linear Regression with BGD(batch gradient descent) )
1.线性回归 假设线性函数如下: 假设我们有10个样本x1,y1),(x2,y2).....(x10,y10),求解目标就是根据多个样本求解theta0和theta1的最优值. 什么样的θ最好的呢?最 ...
- 什么是唯品会JIT业务
以销定采的模式,供应商将商品发给唯品会仓库在由唯品会发给客户:首先在唯品会创建档期绑定PO此时设置的商品库存为虚拟库存,之后供应商根据实际产生的有效订单将订单中的商品发给唯品会,最后再由唯品会发给用户 ...
- Python Scrapy在windows上的安装方法
如果想要学习爬虫,肯定会了解Scrapy,但安装Scrapy的方法相对于安装其他第三方库麻烦一点. 下面总结一下在我的电脑上安装Scrapy的方法,我的电脑是Windows10,32位操作系统.有如下 ...
- linux 进程通信之 mmap
一,管道PIPE 二,FIFO通信 三,mmap通信 创建内存映射区. #include <sys/mman.h> void *mmap(void *addr, size_t length ...
- [linux] 多进程和多线程
1.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段.堆栈段和数据段,这是一种”昂贵”的多任务工作方式.2.而运行于一个进程中的多个线程,它们彼此之间使 ...
- 当请求进入Nginx后,每个HTTP执行阶段的作用
阶段顺序 阶段名称 作用 1 NGX_HTTP_POSTREAD_PHASE = 0 接收并读取请求阶段 2 NGX_HTTP_SERVER_REWRITE_PHASE 修改url阶段,通常有重定向和 ...
- javascript加载XML字符串或文件
1. 加载XML文件 方法1:ajax方式.代码如下: var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObje ...