元类理解与元类编程 《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.在不同的平台环境下,它所依赖的库也各不相同,所以在安装 ...
随机推荐
- 【设计模式】Adapter
前言 Adapter设计模式,允许客户端使用接口不兼容的类. 昨天收拾一些以前的东西,发现了藏在柜子里的一条线,这条线叫做OTG.这条线的一端是micro-usb的输出口,另一端是usb的输入口.这条 ...
- word转txt
import org.apache.poi.hwpf.extractor.WordExtractor; import java.io.IOException; import java.io.Input ...
- CSS 选择器大全
在CSS中,选择器是用于选择要设置样式的元素的模式. 选择器 例子 描述 .class .intro 选择class=“intro”的所有元素 #id #firstname 选择id=“firstna ...
- 微信小程序使用函数防抖解决重复点击消耗性能问题
wxml: <view bindtap="doubleTap" bindtouchstart="touchStart" bindtouchend=&quo ...
- QT4.8.7和VS2010环境搭建及使用
(一)环境搭建 首先下载QT4.8.7的安装包.QT Addin 1.11插件和VS2010安装包.第一步:安装好VS2010第二步:安装QT4.8.7(qt-opensource-windows-x ...
- AccessCenter 模块结构
AccessCenter 模块结构
- mysql主从配置步骤
主服务器配置: 1)登陆MySQL数据库 mysql>mysql -uroot -p123 2)给从服务器设置授权用户 mysql>grant all slave on *.* to us ...
- jetbrains 系列编辑器
下载 webstorm下载地址:https://www.jetbrains.com/webstorm/download/previous.html idea下载地址:https://www.jetbr ...
- 201871010126 王亚涛 《面向对象程序设计(Java)》第十周实验总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- 201871010112-梁丽珍《面向对象程序设计(java)》第七周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...