0%

Python Notebook

look

think

cover

write

check

目录

[TOC]

#串

IPO

P:算法 是核心

    流程图:

        顺序

        选择 if elif

        循环 while/ for

    切割/重用:

        function:

            def, return

            传参,局部参数

            缺点:无记忆

        class:

            三段:类名,data,method

            动作:instance实例化→

                对象:

                    不存类的method和data,但有自己的data。两段:对象名,data

33个保留字

False假 def定义函数 if如果函数 raise

None del import调用 return返回

True真 elif或如果 in在里面 try尝试函数

and条件和 else否则 is while循环

as except不然 lambda简单的匿名函数 with

assert finally最后执行 nonlocal非本地 yield

break终止 for循环 not反

class类 from从 or或

continue global全局函数 pass空函数

###控制流语句if while for

1.if-elif-else语句

if 判断1:

    如果判断1为真,就执行这个

elif 判断2:

    如果判断1为假,就会执行elif 如果判断2为真,就执行这个

else:

    如果前面全为假,就会执行这个

    tip:要有冒号。else后面不用再判断了

2.while-else语句

while 判断:

    如果判断为真,就做这个 做啊做啊做 

    到某时候令判断=假

else:

    判断为假,就执行这个

3.for-in循环语句

for 数 in range(最小的数,最大的数,步长):

    数从最小的数一直变到最大的数(但不包含最大的数!!),每取一个值执行一次这一块

else:

    for结束后执行这个

4.break

跳过最内层循环(包括else的内容)

5.continue

跳过这一次循环中的剩余语句而直接开始下一轮新的循环

函数

def 函数名(变量1,变量2=1):

    这里就是函数的内容了。函数其实就是可以随时调用的程序段,比如len()就是内建函数

    若不写变量2,它会默认为1

nonlocal 变量

global 变量

参数传递

虚实结合,拷贝

可变对象与不可变对象

类型属于对象,变量没有类型

a=2

2是整数型,是对象;a是变量,没有类型,是对象的引用

可变:list dict

list里的list是指针,list里放的全是指针

a=[1,2]

b=a

则指向同一个list对象,而list是可变对象,所以改b也变a

浅拷贝b=a[:],能拷贝一层,第二层还是指向同一个对象

a=[1,[2,3]]

a=2

b=a

则指向同一个int对象,而int是不可变对象,若b=3,是改变b的指向,则a不变

默认参数必须指向不变对象

函数在定义的时候,默认参数lang的值就已经声明了,即空的 [],也就是说 默认参数 指向对象 [],在多次调用默认参数的情况下,就改变了默认参数指向对象的数据,默认参数 指向对象的数据变了,下次再调用时,默认参数已经变了,即不再是你希望的空的[]

(4,) 一个数字的tuple

eval()

到数值

pow(x,y)

x^y

变量作用域

local->enclosing->global->built-in

闭包函数(嵌套函数)

函数内套函数,内函数会用到外函数的变量,外函数返回内函数的引用

特征:外函数的变量由于会被用到而不会被轻易释放

注意:每次调用外函数都会创建一个新的内函数的实例对象,但是闭包变量却只有同一个

用途:装饰器:取执行时间;校验输入

js中用闭包实现面向对象

内部变量修改全局变量,用global

但不建议,因为函数的目的就是封装隔离;若需要使用global变量,请使用形参传参

nonlocal 关键字声明 一个变量, 表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量。

函数可以当变量赋值

函数可以当参数传递

递归函数

内部调用自身

必须有基例,也就是有if

写来简单但执行效果差

习惯:

函数名用小写字母加下划线,

大写字母用在类中

函数之间加空行

类名首字母大写的驼峰命名法;函数名用动宾短语,全小写,_连接

类之间空两行

attribute属性 是变量

method方法 是函数

继承有副作用

类是模板,对象是类的实例instance

类的四个特性

抽象

封装 信息隐藏 提供接口

继承 在类的基础上定义新类,抽象性降低,实现多态

鸭子类型的多态

鸭子类型:

鸭子测试:当一只鸟走起来像鸭子,游泳像鸭子,叫起来像鸭子,那这只鸟就可以称为鸭子

在python中,一个对象有效的语义,不取决于继承的接口,而取决于它本身的data和method

只要有这个方法我就调用,管你是个啥

靠精确的文档和try/except处理异常

装饰器

@classmethod cls 用类名调用,而不是对象

@staticmethod 静态方法,不关注对象和对象内部属性

像访问属性一样调用方法,方法就像属性了 下跟一个跟属性同名的函数

@property 只读

def age(self,a):     if xxx: return "don't!!"   else:  self.__age=a

@方法名.setter:可写

@方法名.deleter: 可删除

也可用property函数来把已经定义好的setter、deleter等绑定给变量

id()查看内存地址

__dict__查看类和对象的内部参数

不允许看到对象里面的东西?

dict对象的时候看不到类里的attribute

dict类的时候看不到method里的变量

magic method 内部留的

__str__

__add__

a=3

isinstance(a,int) 判断是否某类型 这个好啊

不提倡用这个判断某对象是否某类(自定义的) 而是直接调用 用try/except处理异常

类的继承(白盒)

1
class Developer(Employee):   def __init__(,,,,):       super().__init__(,,,) 

支持但不建议用多重继承

3.x版本从深度优先变为广度优先。先从父代所有类找,再从父代的父代找

多用聚合/组合(黑盒)

类中传进一个新类,则删它无涉

在类的内部新生成一个类,则前者删,后者也无

types模块

def prt():

pass

e1.prt=types.MethodType(prt,e1)

不许用。

__私有变量 方法,不可访问

但可以绕过去,君子约定😑

Turtle库

函数:

setup(width,height,startx,starty)

penup()or pu

pendown()or pd

pensize()

pencolor()

fd()or forward

seth()or setheading

circle(radius,extent=None)

##一些赋值上的点

屏幕快照 2018-03-22 上午11.04.39
屏幕快照 2018-03-22 上午11.04.39

a='s'

b=['p','a']

c='m'

*b是列表

屏幕快照 2018-03-22 上午11.04.31
屏幕快照 2018-03-22 上午11.04.31
屏幕快照 2018-03-22 上午11.04.23
屏幕快照 2018-03-22 上午11.04.23

spam='s'

ham='h'


1 in [0,1] == True: False

因为它等于

1 in [0,1] and [0,1] == True

后者错了

str.split:use the comma to divide the str and return a list, useful.

range(a,b)is from a to b-1 !!!! so ugly.

random库

1
print( random.randint(1,10) )        # 产生 1 到 10 的一个整数型随机数  print( random.random() )             # 产生 0 到 1 之间的随机浮点数print( random.uniform(1.1,5.4) )     # 产生  1.1 到 5.4 之间的随机浮点数,区间可以不是整数print( random.choice('tomorrow') )   # 从序列中随机选取一个元素print( random.randrange(1,100,2) )   # 生成从1到100的间隔为2的随机整数a=[1,3,5,6,7]                # 将序列a中的元素顺序打乱random.shuffle(a)

数据处理的常用语句

str

str.isnumeric()当所有都是数字,返回True

str.split(sep=None) 分割 按sep分割,返回列表。默认sep为空格

str.replace(old,new[,count]) 替换并返回副本

str.join(i)将i中元素连接,用str分隔

ord() transform str into ascii chr() contrast

print('aaa'.center(50,'-'))在某长度中居中显示

time库

time.clock()计时开始、结束并返回时间差

即覆盖输出 棒呆

==神tm字母可以直接比大小==

文件读写

with open('hahaha.txt','r') as f:

os模块 处理文件和目录

shutil更高级的

GLOB模块 文件路径查找

glob.glob('')

*匹配多个字符

?匹配单个字符

[0~9]

eyed3 修改mp3文件标签

import xxx as x

pil库

文档格式转换

CSV

程序之间转移表格数据

纯文本

HTML

Json

爬取的地址: https://api.douban.com/v2/book/isbn/+isbn

豆瓣 根据isbn得图书信息

1
{    "rating":               {       "max":10,       "numRaters":1204,       "average":"9.1",       "min":0           },    "subtitle":"",    "author":["[法]米兰·昆德拉"],    "pubdate":"2014-6",    "tags":        [            {"count":239,             "name":"米兰·昆德拉",             "title":"米兰·昆德拉"},            {"count":167,             "name":"哲学",             "title":"哲学"},            {"count":153,             "name":"米兰・昆德拉",             "title":"米兰・昆德拉"},            {"count":147,             "name":"小说",             "title":"小说"},            {"count":145,             "name":"外国文学",             "title":"外国文学"},            {"count":119,             "name":"爱情",             "title":"爱情"},            {"count":98,             "name":"捷克",             "title":"捷克"},            {"count":93,             "name":"人生",             "title":"人生"}        ],                 "origin_title":"",           "image":"https://img1.doubanio.com\/view\/subject\/m\/public\/s27471968.jpg",    "binding":"精装",    "translator":["许钧"],    "catalog":"第一部 轻与重\n第二部 灵与肉\n第三部 不解之词\n第四部 灵与肉\n第五部 轻与重\n第六部 伟大的进军\n第七部 卡列宁的微笑\n大写的牧歌与小写的牧歌 弗朗索瓦·里卡尔",    "pages":"427",    "images":{"small":"https://img1.doubanio.com\/view\/subject\/s\/public\/s27471968.jpg","large":"https://img1.doubanio.com\/view\/subject\/l\/public\/s27471968.jpg","medium":"https://img1.doubanio.com\/view\/subject\/m\/public\/s27471968.jpg"},    "alt":"https:\/\/book.douban.com\/subject\/25900384\/",    "id":"25900384",    "publisher":"上海译文出版社",    "isbn10":"7532766632",    "isbn13":"9787532766635",    "title":"不能承受的生命之轻",    "url":"https:\/\/api.douban.com\/v2\/book\/25900384",    "alt_title":"",    "author_intro":"",    "summary":"《不能承受的生命之轻》是米兰·昆德拉最负盛名的作品。小说描写了托马斯与特丽莎、萨丽娜之间的感情生活。但它不是一个男人和两个女人的三角性爱故事,它是一部哲理小说,小说从“永恒轮回”的讨论开始,把读者带入了对一系列问题的思考中,比如轻与重、灵与肉。\n《不能承受的生命之轻》是一部意象繁复的书,其中装载了多种涵义:被政治化了的社会内涵的揭示、人性考察、个人命运在特定历史与政治语境下的呈现,以及对两性关系本质上的探索等。昆德拉将这些元素糅合在一起,写成一部非同凡响的小说——其中既有隐喻式的哲学思考,也有人的悲欢离合的生命历程的展现。",    "series":      {"id":"24318",         "title":"米兰·昆德拉作品全新系列"},    "price":"46.00元"}

http://mall.baicizhan.com/ws/search?w=apple

百词斩 单词信息

https://api.douban.com/v2/book/isbn/9787532766635,9787508618852,9787540225353

re 正则表达式 极其强大 有点复杂

可以通过 name 属性获取命名空间的名字:

img
img

主文件的命名空间是叫做 'main',而模块的命名空间就是模块名

requests库

幕快照 2018-05-16 下午10.17.0幕快照 2018-05-16 下午10.22.2幕快照 2018-05-16 下午10.27.5

put、post一个字符串,自动放到'data'key下

放几个键值对,自动放到'form'(表单)下

patch比put节省带宽,put必须把整个字段写完整,patch只用写需幕快照 2018-05-18 下午6.03.5幕快照 2018-05-18 下午6.16.1幕快照 2018-05-18 下午6.24.3幕快照 2018-05-18 下午6.26.1幕快照 2018-05-18 下午6.27.0幕快照 2018-05-18 下午6.31.4幕快照 2018-05-18 下午6.35.1幕快照 2018-05-18 下午6.35.3上图中一处错误:

post是不删除的情况下新增

r=requests.get('http://product.dangdang.com/20357456.html')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>> r.encoding
>> 'GBK'

>> r.status_code
>> 200

>> r.headers
>> {'Server': 'nginx', 'Date': 'Thu, 19 Jul 2018 09:30:49 GMT', 'Content-Type': 'text/html; charset=GBK', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Set-Cookie': 'producthistoryid=20357456; expires=Fri, 19-Jul-2019 09:30:49 GMT; Max-Age=31536000; path=/; domain=.dangdang.com', 'Dd-Loc': '7439338628981511792', 'Hit-Cache': 'false', 'Content-Encoding': 'gzip'}

>> r.request.headers #获知头部信息
>> {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

>/#要伪装一个浏览器

>kv={'uesr-agent':'Mozilla/5.0'}
>url='http://product.dangdang.com/20357456.html'
>r=requests.get(url,headers=kv)
屏幕快照 2018-07-19 下午6.19.34
屏幕快照 2018-07-19 下午6.19.34

BeautifulSoup库

可以把html文件输入进来,并且自己整理成好看的格式

soup.select('.xxx')直接nmdcss选择器!!!

from bs4 import BeautifulSoup

大小写敏感,BeautifulSoup是一个类

html文档=标签树=BeautifulSoup类

soup=BeautifulSoup(demo,'html.parser')

解析所有标签格式的源代码

html.parser是自带的html格式的解析器,此外还可以pip一些别的解析器

以下是可以用BeautifulSoup.xx来引用的元素:

屏幕快照 2018-07-29 上午11.58.21
屏幕快照 2018-07-29 上午11.58.21
屏幕快照 2018-07-29 上午11.59.09
屏幕快照 2018-07-29 上午11.59.09

如果有多个相同标签,如多个<p>,只能引用第一个

还可以用soup.a.parent 找标签的父级标签

soup.a.attrs标签属性

soup.a.attrs['class'] 具体某属性

soup.a.name标签名

soup.a.string文字内容 text可以跨越多个标签层次,直接打出里面的文字

这里如果有注释的话,也会直接出来,而没有注释的提示,要区分的话就看type

###html内容遍历

  1. 上行: .parent .parents(用于遍历)
  2. 下行:contents(儿子标签,返回列表) children(用于遍历,每次返回一个标签) descendants(所有次级节点?)
  3. 平行:next_sibling previous_sibling next_siblings previous_siblings

用于遍历的是迭代类型,只能用在for循环中

只有同一个父亲底下的才是平行关系

prettify

bs4将任何文件转换成utf-8

信息标记

让信息具有结构

三种标记形式:

  1. xml(基于html的通用标记表达形式)繁琐
  2. json:有类型的键值对,都有双引号;多值用[,]表示;键值对可嵌套,用{}。适合程序
  3. YAML:键值对,无双引号;所属关系用缩进表达;用-表达并列;|表示整块数据;#是注释。适合阅读
1
key : valuekey : #comment-value1-value2key :  subkey : value

信息提取方法

  1. 标签解析器
  2. 直接搜索
  3. 结合

find_all():

bs4中有find_all(‘a’) 对标签名字的检索 ,返回所有标签的列表 如果是true 则显示所有标签名

find_all(name,attribute,是否搜索所有子孙=true,string)

还可以用正则表达式搜索不完全名字

可以用标签()代替标签.find_all()因为太常用了

屏幕快照 2018-09-27 上午9.54.07
屏幕快照 2018-09-27 上午9.54.07

中文输出对齐问题

用中文空格chr(12288)来填充

正则表达式

通用的字符串表达框架

在字符串的范围内表达「简洁」与「特征」

操作符

操作符 说明 例子
. 单个字符
[] 字符集,给出单个字符的取值范围 [abc]表示a、b、c,[a-z]表示a到z单个字符
[^] 非,给出单个字符的排除范围
* 前一个字符0或多次扩展 py*:p
+ 前一个字符1或多次扩展 py+:py
? 前一个字符0或1次 py?:p
| 左右表达式的任意一个 abc|def:abc或def
{m} 前一个字符m次扩展 py{2}t:pyyt
{m,n} 前一个字符m至n次扩展(包括n) py{1,2}thon:python
^ 匹配字符串的开头 ^py:字符串开头有py
$ 匹配字符串结尾
() 分组,内部只能用| (py)(py|yp)
数字,即[0-9]
单个字符,即[A-Za-z0-9]以及下划线

^[A-Za-z]+$ 由26个字母组成的字符串

^-?\d+$ 整数

^[0-9]*[1-9][0-9]*$ 正整数(必须要有1以上)

[1-9]\d{5} 中国境内邮政编码

[\u4e00-\u9fa5]所有中文

\d{3}-\d{8}|\d{4}-\d{7}国内电话号码

( ([1-9]?\d|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]{1,2}|1[0-9]{1,2}|2[0-4][0-9]|25[0-5])

IP地址

re库的功能函数

###re.search(正则表达式,string,flags=0 控制标记)

在字符串中搜索匹配的第一个位置,返回match对象

控制标记:

re.I (IGNORECASE)忽视大小写

re.M (MULTILINE) ^可以将每一行当做开头

re.S(DOTALL) .可以匹配所有字符

###re.match(正则表达式,string,flags=0 控制标记)

从起始位置起匹配正则表达式,返回match对象

###re.findall(正则表达式,string,flags=0)

列表类型返回全部能匹配的串

###re.split(正则表达式,string,maxsplit=0最大分割数,flags=0)

将字符串按匹配结果进行分割(匹配的部分去掉并作为分割之处),返回列表类型

###re.finditer(pattern,string,flags=0)

返回字符串匹配结果的迭代类型,每个迭代元素是match对象

###re.sub(pattern,repl,string,count=0,flags=0)

repl:用来替换的字符串

count:最大替换次数

在字符串中替换所有匹配正则表达式的子串,返回替换后的字符串

###pat=re.compile(pattern,flags=0)

将正则表达式从字符串编译成对象

###match对象

可以用if match: 判断是否匹配

match.group(0)第一个匹配的元素

重要属性

.string 用来匹配的原文本

.re 匹配时用的pattern(是compile之后的)

.pos 开始搜索文本的位置

.endpos 结束搜索文本的位置

重要方法

.group(0) 获得字符串

.start() 匹配字符串在原字符串的开始位置

.end() 结束位置

.span() 返回(.start(),.end())

re的用法

  1. 一次性操作可以用函数式用法,match=re.search('xx','xx')
  2. 编译后的多次操作用面向对象用法,pat=re.compile(r'pattern') match=pat.search('string')

表示类型

raw string原生字符串类型 r‘text‘:不包含转义符,这样斜杠就是斜杠,比较方便

贪婪匹配和最小匹配

默认采用贪婪匹配方式,从多个匹配的子串中返回最长的那个

例如,match=re.search(r'PY.*N','PYANBNCNDN')(PY开头,N结尾)

会得到'PYANBNCNDN'

如果想用最小匹配,只要加个?,即'PY.*?N'

最小匹配操作符:*? +? ?? {m,n}?

序列化

序列化:将数据转成文本存到文件中,方便下次取用

方法:模块cPickle or pickle

pickle.dumps(dictA)='xxxxxxx' 将dictA转换成文本

pickle.dump(dictA,fileF) 将dictA转换成文本并且直接存储进fileF

反序列化:loads or load

还是序列化成json比较好

多进程与多线程

根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位

在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。

包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

多线程的优点:

  1. 把运行时间长的任务放到后台去处理
  2. 用户界面可以做进度条来显示处理的进度
  3. 加快程序速度
  4. 在一些需要等待的任务实现上很有用,释放珍贵资源,如内存占用

multiprocessing.Pool

用multiprocessing库的Pool类可以创建多进程,

p=Pool(processes=3)创建3个进程

p.apply_async(runTask, args=(i,))让进程执行runTask,args是输入的变量们,i是第i个进程

os.getpid()可获得当前进程的id

p.close()进程结束 p.join()进程间同步 这俩好像最后都得写

multip.Queue

用Queue类实现多进程间的通讯

在一开始用q=Queue()创建Queue类,并且传递给各进程

然后在进程中用q.put(url) q.get()读和写东西进去

它俩有两个参数 blocked和timeout 我没看懂

debug

磨刀不误砍柴工

###调试

####输出

print

assert断言 条件,“不符合条件时抛出的错误”

assertpy 第三方库

可用参数关闭

logging库 可以输出到email、其他文件 等

####文本调试工具

PDB 内置库 pdb.set_trace()然后在这儿随便调变量

IPDB jupyter中

PUDB 可视化全屏调试工具

####图形调试工具

idle

pycharm

微软的一个

测试

单元测试

unitest标准库,pytest第三方库特别火

mock

假对象

FAKER库模拟数据

Vue.js是js的一个库

UI框架

echart 百度给的

动态爬虫

数据处理相关库

Numpy 基于NDarray数据类型

pandas 基于series和dataframe数据类型

scipy高级的机器学习库 很多子模块

matplotlib 画图 但有点丑

tushare 财经数据接口库 返回的绝大部分数据是pandas的dataframe类型

vpython

IO

input() 括号里别乱加东西

eval() 把引号去掉

ls=input().split() 默认以空格分割

a=ls[0]

b=ls[1]

print('a is {}'.format(* **))

数据结构

####基本类型:int float str 都是只读的

强制转换 int()

str.split() strip slice ...都是返回一个copy

####复合类型:list (tuple) set dict

可改 只读 无序无重

list s[::step] 尽可能多掌握 index

for i in ls:

j=ls.index(i) 拿到元素的下标if i in ls[j+1:] …….

tuple: a,b,c (a,b,c) (2,) 只读

dict:{'key':'value'}

list.sort 内部排序 排完还是它本身

sorted(__,key=lambda x:x[0])返回新的

####if elif else while for

s2=s for s in ss if s>2

####函数

def fname(a,b=20,*,**):

return a,b,c

语言简单,难在算法!

XPath

表达式 描述 例子
nodename 选取此节点的所有子节点 classroom
/ 从根节点选取 /classroom
// 选择任意位置的某个节点 //student
. 选取当前节点
.. 选取当前的父节点
@ 选取属性 //@name

谓语:用来选取某个特定节点

用法:方括号

  1. 第n个元素 [n]
  2. 最后一个 [last()]
  3. 倒数第二个[last()-1]
  4. 前两个[position()<3]
  5. 拥有属性name的所有student元素 //student[@name]
  6. 拥有属性name为Zhu的所有student元素 //student[@name='Zhu']

通配符:* 任意元素

多条路径:|

//div/ul[@class='show']

string(.)

CSS选择器

::attr(href)选择href属性

css1
css1
css2
css2
css3
css3

div:contains("str")文本包含了str的div

Scrapy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import scrapyclass 
StackOverflowSpider(scrapy.Spider):
name = "stackoverflow"
start_urls = ["http://stackoverflow.com/questions?sort=votes"]
def start_requests(self): # by this we can create start urls
reqs = []
for i in range(1,200):
req = scrapy.Request('url'+str(i))
reqs.append(req)
return reqs
def parse(self, response):
for href in response.css('.question-summary h3 a::attr(href)'):
full_url = response.urljoin(href.extract())
yield scrapy.Request(full_url, callback=self.parse_question)
def parse_question(self, response):
yield{ 'title': response.css('h1 a::text').extract()[0], 'votes': response.css('.question .vote-count-post::text').extract()[0], 'body': response.css('.question post-text').extract()[0], 'tags': response.css('.question .post-tag::text').extract(), 'link': response.url, }

scrapy runspider somefile.py -o xx.csv

start_urls作为初始链接,并默认把parse()作为回调函数

在parse中用css选择器获得目标url,并注册parse_question()作为目标url的回调函数

command line

scrapy crawl xxxspider -s JOBDIR=job1

可以让任务随时中断又恢复,按ctrl+c就中断,下次再点开这个就继续

--help version version -v

startproject xxx创建一个工程,包括创建一系列文件结构

genspider xxx xxx.comgeneral spider在一个工程中创建一个爬虫,可产生多个爬虫,名字不同

list查看本工程中有哪些spider

view url用浏览器查看当前爬下来的网页

parse url解析,用工程中写好的parse来解析url

shell首先执行scrapy shell url进入,然后常用的是response对象,用response.css('h a::text').extract()直接看到东西有没有

runspider运行一个自包含的爬虫 不用这个,用crawl

bench基准测试,看scrapy有否安装成功

main kits

###Spider

定义了爬取、追踪、提取网站数据的全过程

属性:

name、allowed_domains、start_urls、

custom_settings个性化设置,会覆盖全局settings.py中的设置

crawler抓取器,spider会绑定在上面

settings配置实例,包含project中所有配置变量

logging日志实例

方法

from_crawler() 创建spiders

start_requests() 生成初始requests

make_requests_from_url(url) 根据url生成一个request

parse(response)解析网页内容

self.logger.info('xxx')记录日志

closed(reason) 关闭spider时使用

子类

CrawlSpider XMLFeedSpider CSVFeedSpider SitemapSpider

Selecter

extract_first(default='not found')可以解决没找到值而终止循环的问题

Item

完整定义:

1
2
3
4
5
import scrapyclass Product(scrapy.Item):    
name = scrapy.Field()
stock = scrapy.Field()
last_updated = scrapy.Field(serializer=str)
#don't worry, we will learn this latter.

Item Pipeline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from scrapy.exceptions 
import DropItemclass
PricePipeline(Object): vat_factor=1.5
def process_item(self,item,spider):# necessary
if item['price']:
if item['price_excludes_vat']:
item['price']*=self.vat_factor
return item
else:
return DropItem('Missing price in {}'.format(item))
# 触发一个异常
class DuplicatesPipeline(object):
def __init__(self):
self.ids_seen=set()
def process_item(self,item,spider):
if item['id'] in self.ids_seen:
raise DropItem('Duplicate item found:{}'.format(item))
else self.ids_seen.add(item['id'])
return item

启用Item Pipeline:在settings中设置:

1
ITEM_PIPELINES = {    'myproject.pipelines.PricePipeline': 300,    'myproject.pipelines.DuplicatesPipeline': 800    # pipeline : 优先级(0~1000,小的先)}

Feed Exports

保存为csv:

writeToCsv.py

1
import csv   from PROJECT_NAME import settings   class WriteToCsv(object):        def process_item(self, item, spider):            writer = csv.writer(open(settings.csv_file_path, 'a'), lineterminator='\n')              writer.writerow([item[key] for key in item.keys()])            return item

settings.py

1
ITEM_PIPELINES = { 'project.pipelines_path.writeToCsv.WriteToCsv' : A_NUMBER_HIGHER_THAN_ALL_OTHER_PIPELINES}   csv_file_path = PATH_TO_CSV

main object

Requestsobject

class scrapy.http.Requests(url,[callback,method='GET',headers,body,cookies,meta,encoding='utf-8',priority=0,don't_filter=False,errback])

copy() 返回一个和原requests一模一样的

replace() 返回一个可以自己定制的

return scrapy.Request(url,meta={'theitem': item})

item = response.meta['theitem']

可以在两个parse 函数中传递item对象

重要子类:FormRequest 用来实现登录 参数:url,[formdata]

登录的例子:

1
import scrapyclass LoginSpider(scrapy.spider):    name = 'xxx'    start_urls = ['xxx']        def parse(self,response):        return scrapy.FormRequest.from_response(            response,            formdata={'username':'xxx','password':'xxx'},            callback=self.after_login        )        def after_login(self,response):        #check login succeed before going on        if 'authontication failed' in response.body:            self.logger.error('Login failed')            return        #continue....

Response对象

一般不实例化,只是使用,是Request返回的一个对象

urljoin(url)一般从网页中抽取的都是相对链接,用这个生成绝对链接

inner service

logging

import logging

logging.warning('xxx')

logging.log(logging.WARNING,'xxx')

但在scrapy中,scrapy.Spider类已经内置了logger类,而MySpider又会继承它,所以直接用self.logger.info('xxx')就行

还可以在settings中配置logger,主要有LOG_FILE确定log文件,这个一设置,就会产生日志文件了

1
divs=response.css('xxx')if not divs:    self.logger.info('Page error. {}'.format(url))
1
try:    item['xx']=xxx;except Exception,e:    print('Error:',e)

Stats Collector

Sending Email

import:from scrapy.mail import Mailsender

start:mailer=MailSender(host,from,user,password,port)ormailer=MailSender.from_settings(settings)

use:mailer.send(to=['xxx@163.com'],subject='xxx',body='xxx',cc=['xx@a.com'])

settings:MAIL_FROM MAIL_HOST MAIL_PORT MAIL_USER MAIL_PASS MAIL_TLS MAIL_SSL

Architecture

scrapy_architecture_02
scrapy_architecture_02
v2-8c591d54457bb033812a2b0364011e9c_1200x500
v2-8c591d54457bb033812a2b0364011e9c_1200x500

下载图片

使用内置的pipeline。在settings中写:

1
ITEM_PIPELINES = {'scrapy.pipelines.images.ImagePipeline':1}IMAGES_URLS_FIELD = 'xxx' # the name of the image's url field in the itemIMAGES_STORE = r'.' # 存储在当前路径

proxy

  1. 爬取西刺网站上的ip列表,存到csv文件中

  2. 一个proxy.py文件~实现对ip的获取和检查

  3. 将meta中的proxy填充好,并且在settings中添加proxy相关的middleware,就可以使用了

http: 4 https: 5 {'http': [['110.52.235.222', '9999', 'HTTP'], ['27.155.84.233', '8081', 'HTTP'], ['121.61.2.154', '9999', 'HTTP'], ['116.209.57.232', '9999', 'HTTP']], 'https': [['121.61.2.185', '9999', 'HTTPS'], ['121.61.0.33', '9999', 'HTTPS'], ['110.52.235.154', '9999', 'HTTPS'], ['111.77.197.133', '9999', 'HTTPS'], ['221.224.136.211', '35101', 'HTTPS']]}

selenium

from selenium import webdriver

driver=webdriver.Chrome()

driver.get(url)

driver.page_source

常用属性和方法:

1
from selenium.webdriver.common.by import By
  1. find_element_by_id # ID
  2. find_elements_by_class_name # class
  3. find_elements_by_tag_name # 标签名
  4. find_elements_by_name # name
  5. find_elements_by_link_text # a标签中的text查找(精确匹配)
  6. find_elements_by_partial_link_text #a标签中的text查找(部分匹配即可)
  7. find_elements_by_css_selector # css选择器查找
  8. find_elements_by_xpath # find_elements_by_xpath("//input"),请翻阅文档

scrapyd

command line:scrapyd to execute it.

###部署

upload a spider: cd into the local

配置服务器和项目信息, 需要编辑scrapy.cfg文件,添加如下内容

[deploy:主机名]url=http://localhost:6800/

可以用scrapyd-deploy -l列出所有可用主机target

scrapyd-deploy target主机地址 -p 工程名

我们也可以把项目信息写入到配置文件中,部署时就不用指定项目信息,编辑scrapy.cfg文件,添加项目信息

[deploy:server-douban]url=http://localhost:6800/project=douban-movies

下次部署可以直接执行

$ scrapyd-deploy

###调度

调度工具:curl

shedule api:curl http://localhost:6800/schedule.json -d project=xxx -d spider=somespider

cancel api:curl http://localhost:6800/cancel.json -d project=xxx -d job=之前的任务的id

list:curl http://129.28.28.203/listprojects.json

curl http://129.28.28.203:6800/schedule.json -d project=zhihu -d spider=topicfollower

curl http://129.28.28.203:6800/delproject.json -d project=zhihu

SQLite3

1
import sqlite3conn = sqlite3.connect('myquotes.db')curr = conn.cursor()curr.execute("""create table quotes_tb(                title text,                author text,                tag text                )""")curr.execute("""insert into quote_tb values(                xxx,zhu,notag                )""")conn.commit()conn.close()
屏幕快照 2019-02-17 下午3.07.13
屏幕快照 2019-02-17 下午3.07.13

use sqlite3 in scrapy pipelines:

1
import sqlite3class SavetoSQLitePipeline(object):    def __init__(self):        self.create_connection()        self.create_table()            def create_connection(self):        self.conn=sqlite3.connect('mydatabase.db')        self.curr=self.conn.cursor()            def create_table(self):        self.curr.execute("""drop table if exists my_tb""")        self.curr.execute("""create table my_tb(                            aaa text,                            bbb text,                            ccc text                            )""")            def process_item(self,item,spider):        self.store_db(item)        print('Pipeline :'+item['title'])        return item        def store_db(self,item):        self.curr.execute("""insert into my_tb values(?,?,?)""".(                        item['aaa'],                        item['bbb'],                        item['ccc']                        ))        self.conn.commit()

Machine Learning

classify

  • Supervised Learning: data is labeled and the program learns to predict the output from the input data
    • Regression : predict a continuous-valued output.
    • Classification: predict a discrete number of values.
  • Unsupervised Learning: data is unlabeled and the program learns to recognize the inherent structure in the input data
    • Clustering is a common unsupervised machine learning approach that finds patterns and structures in unlabeled data by grouping them into clusters.

scikit-learn

Scikit-learn is a library in Python that provides many unsupervised and supervised learning algorithms. It's built upon some of the technology you might already be familiar with, like NumPy, pandas, and Matplotlib!

As you build robust Machine Learning programs, it's helpful to have all the sklearncommands all in one place in case you forget.

Linear Regression

Import and create the model:

1
from sklearn.linear_model import LinearRegressionyour_model = LinearRegression()

Fit:

1
your_model.fit(x_training_data, y_training_data)
  • .coef_: contains the coefficients
  • .intercept_: contains the intercept

Predict:

1
predictions = your_model.predict(your_x_data)
  • .score(): returns the coefficient of determination R²

Naive Bayes

Import and create the model:

1
from sklearn.naive_bayes import MultinomialNByour_model = MultinomialNB()

Fit:

1
your_model.fit(x_training_data, y_training_data)

Predict:

1
# Returns a list of predicted classes - one prediction for every data pointpredictions = your_model.predict(your_x_data)# For every data point, returns a list of probabilities of each classprobabilities = your_model.predict_proba(your_x_data)

K-Nearest Neighbors

Import and create the model:

1
from sklearn.neigbors import KNeighborsClassifieryour_model = KNeighborsClassifier()

Fit:

1
your_model.fit(x_training_data, y_training_data)

Predict:

1
# Returns a list of predicted classes - one prediction for every data pointpredictions = your_model.predict(your_x_data)# For every data point, returns a list of probabilities of each classprobabilities = your_model.predict_proba(your_x_data)

K-Means

Import and create the model:

1
from sklearn.cluster import KMeansyour_model = KMeans(n_clusters=4, init='random')
  • n_clusters: number of clusters to form and number of centroids to generate
  • init: method for initialization
    • k-means++: K-Means++ [default]
    • random: K-Means
  • random_state: the seed used by the random number generator [optional]

Fit:

1
your_model.fit(x_training_data)

Predict:

1
predictions = your_model.predict(your_x_data)

Validating the Model

Import and print accuracy, recall, precision, and F1 score:

1
from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_scoreprint(accuracy_score(true_labels, guesses))print(recall_score(true_labels, guesses))print(precision_score(true_labels, guesses))print(f1_score(true_labels, guesses))

Import and print the confusion matrix:

1
from sklearn.metrics import confusion_matrixprint(confusion_matrix(true_labels, guesses))

Training Sets and Test Sets

1
from sklearn.model_selection import train_test_splitx_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.8, test_size=0.2)
  • train_size: the proportion of the dataset to include in the train split
  • test_size: the proportion of the dataset to include in the test split
  • random_state: the seed used by the random number generator [optional]

Matplotlib

##Objects

Figure:一张布,可以放很多张图

Axes: 一张图,表示一个数据关系,可以放很多个坐标轴

Axis: 一个坐标轴

Artist: 所有可见的东西,包括前面那些,还有文字、标签等等。不能在Axes之间共享

##Input

input type: np.array or np.ma.masked_array

to convert a pandas.DataFrame

1
a = pandas.DataFrame(np.random.rand(4,5), columns = list('abcde'))a_asarray = a.values

and to convert a np.matrix

1
b = np.matrix([[1,2],[3,4]])b_asarray = np.asarray(b)

##Backends

If your script depends on a specific backend you can use the use() function:

1
import matplotlibmatplotlib.use('PS')   # generate postscript output by default

If you use the use() function, this must be done before importing matplotlib.pyplot.

###matplotlib renderers:

Renderer Filetypes Description
AGG png raster graphics -- high quality images using the Anti-Grain Geometry engine
PS ps eps vector graphics -- Postscript output
PDF pdf vector graphics -- Portable Document Format
SVG svg vector graphics -- Scalable Vector Graphics
Cairo png ps pdf svg raster graphics and vector graphics -- using the Cairo graphics library
Backend Description
TkAgg Agg rendering to a Tk canvas (requires TkInter). This backend can be activated in IPython with %matplotlib tk.
nbAgg Embed an interactive figure in a Jupyter classic notebook. This backend can be enabled in Jupyter notebooks via %matplotlib notebook.

Pyplot

Plot

versitile

1
plt.plot([1, 2, 3, 4])

默认输入是y,x会从0开始,自己长。折线图

1
plt.plot([1, 2, 3, 4], [1, 4, 9, 16])

x-y

1
plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro')plt.axis([0, 6, 0, 20])

第三个参数是可选的格式配置参数,默认是'b-' Blue line;现在的'ro'是Red Circle

axis指定x轴范围和y

Pandas

data structure

1. Series

s=pd.Series([1,2,3,4],index=['a','b','c','d']

一维,带标签,可以装任何类型数据。可以用列表转换,也可以重新指定索引s.index()

2. DataFrame

1
d={'a':[1,2,3],   'b':[4,5,6],   'c':[7,8,9]}df=pd.DataFrame(d,columns=['a','b','c'])

二维。可以用字典转换.f.columns()

Selection

image-20191122235116830
image-20191122235116830

列名选择

1
selected_cols = ['2010', '2011', '2012']date_df = df[selected_cols]

:robot:

Happy Coding!

其他发布渠道