Python IDE
1 Eclipse + PyDev : 扩展PyDev插件
install new software --> add --> name: Pydev Location: http://pydev.org/updates
配置插件后需要pydev解析器:
windows-->preferences -->点击 pydev-->interpreter-Python --> new-->python.exe(python安装目录)
以上完成就可用eclipse开发python代码
创建项目:
File-->new-->projects... -->PyDev-->PyDevProject-->输入项目名 即可完成项目的创建
2 PyCharm 跨平台 下载地址:http://www.jetbrains.com/pycharm/download/#
IO编程:
Input/Output 凡涉及数据交换都会涉及IO编程,Stream(流)是其中重要的概念,分为Input Stream/Output Stream
数据相当于水只能单向流动,流相当于水管,所以传输过程种要架设两只水管,一个负责输入一个负责输出实现同步。
文件读写:
1 打开文件:python内置读写文件的函数,但读写之前要打开,以确定文件的读写模式。open函数用于打开文件
open(name[.mode[.buffering]]) / open(r'C:\Users\ASUS\Desktop\note.txt')
mode: r / w / a(追加) / b(二进制:可添加到其他模式使用) /+(读/写模式:可添加到其他模式使用)
buffering:控制文件缓冲 0 就无缓冲‘直接写在硬盘’ 1 有缓冲‘先写入内存 使用flush/close函数写到硬盘’
大于1 就代表缓冲字节,为负数代表使用默认缓冲大小
2 文件读取:分按‘字节’或‘行’读取 常用方法:read(),readlines(),close()
try:f=open(r'c:\text\qiye.txt','r') print f.read() finally:if f: f.close()
简化上面:with open(r'c:\text\qiye.txt','r') as fileReader: print fileReader.read()
对于大文件读取:直接read()不合适,可能会出现内存不足的问题,一般会使用readline()
优化:with open(r'c:\text\qiyi.txt','r') as fileReader: for line in fileReader.readlines(): print line.strip()
3 文件写入:open时传入标识符‘w’or 'wb' 表示写入文本或二进制,可反复调用write()写入,最后close()关闭
f = open(r'c:\text\qiyi.txt','w') f.write('qiyi') f.close()
优化:with open(r'c:\text\qiyi.txt','w') as fileWriter: fileWriter.write('qiyi')
操作文件目录:用到 os 模块 和shutil模块
os.getcwd() 当前脚本工作目录路径
os.listdir() 返回指定目录下所有文件和目录名
os.remove(filepath) 删除一个文件
os.removedirs(r"d:\python") 删除多个空目录
os.path.isfile(filepath) 是否文件
os.path.isdir(filepath) 是否目录
os.path.isabs(filepath) 是否绝对路径
os.path.exists(filepath) 是否存在
os.path.split(filepath) 分离目录和文件名 返回数组
os.path.splitext() 分离扩展名
os.path.dirname(filepath) 获取路径名
os.path.basename(filepath) 获取文件名
os.getenv()/os.putenv() 读取和设置环境变量
os.linesep 读取平台行终止符
os.name 指示正在使用的平台
os.rename(old,new) 重命名文件或目录
os.makedir(r"c:\python\test") 创建多级目录
os.mkdir("test") 创建单个目录
os.stat(file) 获取文件属性
os.chmod(file) 修改文件权限和时间戳
os.path.getsize(filename) 获取文件大小
shutil.copytree("olddir","newdir")复制文件夹
shutil.copyfile("oldfile","newfile")复制文件
shutil.move("oldpos","newpos") 移动文件/目录
os.rmdir("dir") 只能删除空目录
shutil.rmtree("dir") 有内容目录也能删除
序列化操作:程序运行时变量都在内存中,程序中断内存被回收,程序再运行时变量会被初始化,所以内存变量变可存储
或可传输的过程就是序列化。序列化后可把内容写入磁盘,或网络传输到别的辑器,实现状态的保存和共享,反
过来,将内容从序列化对象从小读取到内存中称之为‘反序列化’
python中使用 cPickle and pickle 来实现序列化,两种功能一样,前者是由c语言编写,效率高很多
导入:try:import cPickle as pickle except ImportError: import pickle
序列化方法:dumps or dump , dumps方法将任意对象序列化成一个str 然后保存str
import cPickle as pickle
d = dict(url='index.html',title='首页',content='首页')
pickle.dumps(d)
而使用dump可将序列化后的对象直接写入文件中:pickle.dump(d,file)
反序列化的方法:loads and load
进程和线程:很重要可提高爬虫的工作效率,会提到:多进程,多线程,协程,分布式进程等四个方面
1 os 模块的 fork 方式实现多进程:fork方法会复制当前进程,两个进程几乎完全相同,父进程返回子进程ID,子进程返回0
os模块中 getpid()用于获取当前进程ID,getppid() 用于获取父进程的ID
2 multiprocessing 模块创建多进程:模块提供Process类描述进程对象,只需要传入一个执行函数和函数的参数就可完成
一个Process实例的创建,用start()方法启动进程,join()方法实现进程间的同步。
3 multiprocessing 模块提供Pool类代表进程池对象(代码:P30)
这里会出现一个在windows底下运行时无法创建进程的问题:原因一:缺乏linux中 fork机制,可执行freeze_support支持
原因二:multiprocessing模块不支持交互模式,在cmd中执行py文件就可以创建进程了
4 进程间通讯:Queue,Pipe,Value+Array等方式
Queue: put,Get方法进行操作 ,多个进程可以往Queue中写数据,也可以在Queue中读取数据(代码:P32)
Pipe:方法返回(conn1,conn2)代表管道的两个端口,duplex为True代表全双工,两个端口均可收发消息,
duplex为false时 conn1接收消息,conn2发送消息。send() and recv() 为发送和接收消息的方法
线程同步:多线程共同对某个数据修改,为保证数据的正确性,需要对多个线程进行同步。使用Thread对象的Lock和RLock
可实现线程的简单同步。两个对象都有acquire方法和release方法,对于只允许一个线程操作的代码可放在两个
方法之间。对Lock而言若两次连续使用acquire会导致死锁,对于RLock允许连续acquire操作,对象内部会维护
(代码:P36)
全局解释器锁(GIL):python原始解析器CPython中存在GIL,解释执行python代码时会产生互斥锁来限制线程对共享资源
的访问,直到解释器遇到I/O操作或者操作次数达到一定数目时才会释放GIL。由于GIL存在进行多线程操作时不能
调用多个CPU内核,所以CPU密集操作时不推荐使用多线程,倾向多进程。然而对于IO密集型操作,多线程可以明
显提高效率,如Python爬虫开发。
协程coroutine:又叫微线程,纤程,是一种用户级的轻量级线程。协程拥有自己的寄存器和上下文栈,切换时会寄存器上下
文和栈保存到其他地方,切回来时恢复。并发编程中,协程和线程类似每个协程表示一个执行单元,有自己本地数
据,与其他协程共享全局数据和其他资源
协程其实算单线程,需要用户自己写调度逻辑,CPU不用去考虑切换调度等,在一定程度上优于多线程。
python通过yield提供对协程的基本支持,gevent是一个基于协程的Python网络函数库,
使用greenlet在libev事件循环顶部提供了一个有高级别并发性的API,主要特点:
基于libev的快速事件循环,基于greenlet的轻量执行单元,API复用了Python标准库里内容
支持SSL协作式sockets,通过线程池或c-ares实现DNS查询,通过monkey patching让第三方模块
变成协作式
greenlet对协程的支持本质上是在事项切换工作,是一种合理安排串行方式。(代码:P38)
gevent提供了对池的支持,当拥有动态数量的greenlet需要进行并发管理时,就可以用池。(代码:P39)
分布式进程:将Process进程分布在多台机器上,充分利用机器性能完成复杂任务,可以运用在分布式爬虫开发中
multiprocessing模块不但支持多进程,managers子模块还支持把多进程分部到多台机器上,可以写一个服务进
程作为调度者,将任务分布到其他多进程中,依靠网络通讯进行管理。(代码:P40)
网络编程:Socket(套接字)是网络编程的一个抽象概念,用一个Socket表示打开一个网络连接。而打开一个Socket需要知道
目标计算机个IP地址和端口号,再指定协议类型即可。
python有两个基本Socket模块:Socket,SocketServer
1 套接字类型:Socket(family,type[,protocal]) 地址族,套接字类型,协议编号(默认为0)
2 Socket函数
TCP编程:网络编程通常分两部分:服务端,客户端
服务端:创建和运行需要五个步骤:创建Socket绑定IP和端口,开始监听连接,进入循环接收客户端请求,
接收传来的数据并发送给对方数据,传输完成关闭Socket(代码:P46)
客户端:三个步骤:创建Socket连接远端地址,连接后发送数据和接收数据,传输完毕后关闭Socket
UDP编程:TCP通常需要以流的形式发送数据并且需要建立可靠的连接过程。UDP则是面向无连接的协议,只需要知道IP和
端口就可以直接发送数据包,但不关心是否能达到目的端,所以UDP不可靠,由于不连接所以速度比TCP快
服务端:创建Socket绑定指定的IP和端口,直接发送数据和接收数据,关闭Socket (代码:P48)
客户端:创建Socket就可以直接和服务端进行数据交换
爬虫的架构及运行流程:
基础爬虫架构包括五大模块:爬虫调度器,URL管理器,HTML下载器,HTML解析器,数据存储器
爬虫数据存储(无数据库版本):一部分HTML文本内容存储,另一部分是多媒体文件存储
存储为JSON:(代码:P140)Python对JSON文件操作是编码和解码,通过JSON模块来实现。‘编码’是把
Python对象转换程JSON对象的一个过程,常用函数是:dumps,dump。dump转换对象并写入文件,dumps
只生成了一个字符串。将json对象转换成python的一个过程,常用的函数是load和loads函数(代码:P144)
1 存储为CSV:import csv with open('qiye.csv','w') as f: f_csv=csv.writer(f) f_csv.writerow(header)
2 读取CSV:f_csv=csv.reader(f) headers=next(f_csv) for row in f_csv: print(row)
3 多媒体文件抽取:存储媒体文件有两种方式:获取文件的URL连接,直接将媒体文件下载到本地。
主要用到urllib模块提供的urlretrieve()函数,直接将远程数据下载到本地:
urlretrieve(url,filename=None,reporthook=None,data=None)
4 Email提醒:Email主要起到提醒作用(代码:P150)
基础爬虫:
URL管理器:两个变量:已经爬取的URL集合,未爬取的URL集合。采用Python的set类型用于去重
连接去重有三种,一内存去重,二关系数据库去重,三缓存数据库去重。大型成熟爬虫采取第三种方式去重,以避免
内存大小的限制,且比关系数据库去重效率高很多。基于我们爬取量小可以使用内存set方式去重
除了两个URL集合,还需要提供以下接口,配合其他模块使用:
判断代取URL:has_new_url(),添加新的URL到未爬取:add_new_url(url) add_new_urls(urls),获取未爬取
URL:get_new_url(),获取未爬取URL集合大小:new_url_size(),获取以爬取URL大小:old_url_size()
管理器(代码:P153)
HTML下载器:用来下载网页,需要注意网页的编码,以保证不会乱码,需要用到Requests模块,只需要实现一个接口:download(url)
下载器(代码:P154)
HTML解析器:使用BeautifulSoup4进行HTML解析,需要的部分主要分为提取相关词条页面的URL和提取当前词条的标题和摘要
解析器(代码:P156)
数据存储器:主要包括两个方法:store_data(data)用于解析出来的数据存储到内存中,output_html()用于将存储数据输出为指定
文件格式。(代码:P157)
爬取调度器:爬虫调度器来协调管理这些模块。先初始化各模块,然后通过crawl(root_url)方法传入入口URL。方法内部按照运行
流程控制各个模块的工作。(代码:P158)
分布式爬虫:下面的实现采用比较简单的‘主从模式’,涉及到‘分布式进程’和‘进程通信’的内容。
主从模式:一台主机作为‘控制节点’负责管理所有运行网络爬虫的主机,爬虫只需要从控制系欸但那里接收任务
并把新生成的任务提交各控制节点就行。这个过程爬虫不需要和其他爬虫通信,这样实现简单,利于管理。而控制
节点需要与所有爬虫进行通信,所以主从模式有缺陷,控制节点会成为整个系统的瓶颈,导致整个分布式爬虫性能
下降。
控制节点:(ControlNode)主要分为URL管理器,数据存储器,控制调度器。控制调度器通过三个进程来协调URL管理器
和数据存储器的工作:一个是‘URL管理进程’负责URL管理和将URL传递给爬虫节点,一个是‘数据提取进程’将
返回内容数据交给数据存储进程和将返回数据中的URL交给URL管理进程,最后一个是‘数据存储进程’,负责提取
进程中提交的数据进行本地存储。(详解:P161)
URL管理器:优化了基础爬虫代码,采用‘内存set去重’若url过多,容易导致内存溢出,所以将爬取过的url经过MD5处理
控制长度,将MD5内存摘要存储到set能减少几倍内存消耗。但python的MD5算法生成的是256位取其中128位即可
同时添加save_progress和load_progress方法进行序列化操作,将未爬取和已爬取的URL集合序列化到本地保存当前
的进度以便下次恢复状态。(代码:P162)
数据存储器:代码同基础爬虫(代码:P163)
控制调度器:产生并启动URL管理进程,数据提取进程和数据存储进程,同时维护4个队列保持进程间通讯:
url_q:url管理进程将url传递给爬虫节点的通道
result_q:爬虫节点将数据返回给数据提取进程的通道
conn_q:数据提取进程将新的url数据提交给URL管理进程的通道
store_q:数据提取进程将获取到的数据交给数据存储进程的通道
同时还需要一个分布式管理器方法:start_manager()
控制调度器(代码:P165)
爬虫节点:(SpiderNode)比较简单,主要包括HTML下载器,HTML解析器,爬虫调度器
爬虫调度器获取控制节点的URL,爬虫调度器调用HTML解析器,HTML下载器获取网页内容,爬虫调度器将新的URL
传入控制节点
1 HTML下载器:和基础爬虫内容一致(代码:P167)
2 HTML解析器:和基础爬虫内容一致(代码:P168)
3 爬虫调度器:需要用到分布式进程中工作进程的代码。调度器需要先连接控制节点,然后从url_q队列中获取URL下载
并解析,然后将获取的数据交给request_q队列并返回给控制节点。(代码:P169)
运维(环境搭建): 可以在一台机器上测试代码的正确性,也可以使用三台VPS服务器,两台运行爬虫的节点程序(IP改为控制节点主机公网IP),
一台运行控制节点程序,进行分布式爬取,这样更贴近真实的爬取环境。
中级篇
数据库存储:SQLite,MySQL,MongoDB主要介绍这三种数据库使用
SQLite:是一个开源的嵌入式关系数据库,实现自包容,零配置,支持事务的SQL数据库引擎。特点:高度便捷,结构紧凑高效可靠
安装运行简洁,并发性能不太高。单文件数据库引擎,一个文件就是一个数据库,方便储存和转移。
下载:http://www.sqlite.org/download.html ; 下载 sqlite-dll-*.zip 和 sqlite-tools-win32-*.zip 两个压缩包
安装:硬盘上创建一个文件夹放置两个压缩文件并解压缩,将目录添加到环境变量PATH中,cmd输入sqlite3验证安装
SQL:SQL语言有很多版本,每个数据库都有自己独特的SQL语法,但为了和ANSI标准兼容他们必须以相似的方式共同
支持一些主要的关键词比如:SELECT。SQL主要分为两部分:数据库定义语言(DDL)和数据库操作语言:
(DML)SQL语法对大小写不敏感。
SQLite增删查改:cmd中输入:sqlite3 D:\test.db 就可创建数据库。
创建表:create table person(id integer primary key,name varchar(20),age integer);
增加:insert into person(name,age) values('qiye',20);
修改:update person set age=17 where name='qiye';
查询:select * from person;
删除:delete from person where name='qiye';
常用SQLite命令:显示表结构: sqlite>.schema [table] 获取所有表和视图: .tables 获取指定表的索引列表:.indices [table]
导出数据库到SQL文件:.output [filename] .dump .output stdout
从SQL文件导入到数据库:.read [filename]
格式化输出数据库到CSV格式:.output [filename.csv] .separator, select * from test; .output stdout
从CSV文件导入到数据库:create table newtable (id integer primary key,name varchar(20),age integer);
.import [filename.csv] newtable
备份数据库:sqlite3 test.db .dump > backup.sql
恢复数据库:sqlite3 test.db < backup.sql
SQLite事务:事务指的是单个逻辑单元执行的一系列操作。SQLite控制事务命令:BEGIN TRANSACTION : 启动事务处理
COMMIT : 保存更改/END TRANSACTION ROLLBACK:回滚所作的更改
Python3操作SQLite:
导入sqlite数据库模块(python3内置模块):import sqlite3
创建打开数据库:connect方法(创建/打开数据库):con=sqlite3.connect('D:\test.db')
内存中创建:con=sqlite3.connect(':memory:')
数据库连接对象:con就是数据库连接对象。方法:cursor()创建游标对象,commit()提交事务,rollback()回滚,close()关闭
游标对象使用: cur=con.cursor() 拥有方法:execute()执行sql,executemany()执行多条sql,close()关闭游标,fetchone()
获取一条记录,并将游标指向下一条记录。fetchmany()取多条记录。fetchall()取所有记录。scroll()游标滚动
建表:使用游标对象创建一个person表:cur.execute('...')
插入数据:两种方法:直接构建SQL执行(容易造成SQL注入)替代方法:使用占位符,也可用excutemany()执行多条sql
cur.execute(' insert into person values (%s)' %data)
cur.execute(' insert into person values(?,?,?)' ,(0,'qiye',20))
cur.executemany('insert into person values (?,?,?)',[(3,'marry',20),(4,'jack',20)])
con.commit() 提交后数据会生效
查询数据/修改/删除数据库:cur.execute('select * from person')
执行完所有操作后需要关闭数据库,插入或者修改中文数据时,要在中文字符前加上‘u’
MySQL:关系型数据库管理系统:cmd : 启动:net start MySQL 停止:net stop MySQL 卸载:sc delete MySQL
登录MySQL:mysql -u root -p
登录时执行SQL文件:mysql -u root -p
修改密码:mysqladmin -u 用户名 -p oldPassword newPassword
新增用户:grant 权限1,权限2,... on databaseName.tableName to 用户名@用户地址 identified by '密码';
备份数据库:mysqldump -h 主机名 -P 端口 -u 用户名 -p 密码 -database 数据库表命>文件名.sql
Python操作MySQL:
导入MySQLdb数据库模块:先安装:pip install MySQL-python 导入:import MySQLdb
打开数据库:con=MySQLdb.connect(host='localhost',user='root',passwd='',db='test',port=3306,charset='utf-8')
数据库连接对象:con;方法:cursor()创建游标对象,commit()事务提交,rollback()事务回滚,close()关闭
游标使用:execute()执行SQL,executemany(),close()关闭游标,fetchone(),fetchmany(),fetchall(),scroll()回滚
数据库操作同SQLite
MongoDB:更适合爬虫
MongoDB是一个基于分布式文件存储的数据库,介于关系型和非关系型之间的产品,属于非关系数据库。非常适合在
爬虫开发中用作大规模数据的存稿
安装MongoDB:下载安装包安装。下载地址:http://www.mongodb.org/downloads
可以将mongod --dbpath D:\mongodb\data\db 做成批处理文件方便使用
还可以将mongoDB注册成一个服务,在系统启动时自动运行:mongod --bind_ip yourIPadress --logpath
--logappend --dbpath
"YourServiceName" --install (详情:P198)
注册:mongod--logpath "D:\mongodb\log.txt" --dbpath "D:\mongodb\data\db" --install
然后输入:net start mongodb就可以启动服务了。输入mongo 就可进入shell操作界面
MongoDB基础:属于NoSQL数据库,MongoDB基本概念是:集合,文档,数据库。普通数据库:表单,数据行,数据库
文档:MongoDB数据的基本单元(BSON)类似库中的行。文档有唯一标识:_id ,数据库可自动生成。
文档以key/value方式,类比数据库中列名和值。文档特性:一,键值对有序顺序不同文档不同。二
文档值可以是字符串,数组,整数以及文档等类型。三,键用双引号标识(个别例外),可用任务
UTF-8字符,键不能含有‘\0’(空字符:这个字符用来标识结尾);‘.’'$'有特别含义,‘_’开头最
好不用,文档区分大小写以及值类型
集合:在MongoDB中是一组文档。类似于数据表,集合存在于数据库中没有固定结构可以插入不同格式类型数据
合法集合名:不能是空字符,不能含有‘\0’,不能以’system.‘开头,不能含有保留字符
数据库:一个MongoDB可以建立多个数据库,默认数据库为‘db’在data目录中(安装时创建)MongoDB单
个实例可以容纳多个独立数据库,每一个都有自己的集合和权限。不同数据库放在不同的文件中。在
MongoDB的shell窗口中使用show dbs命令可以查看所有的数据库,使用db命令可以查看当前的数
据库
创建数据库:use DATABASE_NAME (不存在创建,存在就切换),查看所有数据库:show dbs
删除数据库:db.dropDatabase() (删除当前数据库) db命令可以查看所有数据库
集合文档的增删改查:所有存储在集合中的数据都是BSON格式(是类JSON的一种二进制形式)
插入文档:insert() 或 save() 语法:db.COLLECTION_NAME.insert(document)
查询文档:find() 查询 语法:db.COLLECTION_NAME.find(),以易读方式查询可用:pretty()
语法:db.COLLECTION_NAME.find().pretty() 相当于 select * from table
查询条件和操作符:...find({"likes":100}) 等于:{
{$lt:
大于或等于:{
多个key以逗号隔开代替 AND:db.COLLECTION_NAME.find({key1:value,key2:value2})
OR条件:db.COLLECTION_NAME.find({ $or:[{key1:value1},{key2:value2}] }).pretty()
AND和OR条件可以联合使用。
更新文档:update() 和 save() 更新集合中的文档。update()用于更新已存在的文档:db.collection.
update(query,update,{upsert:boolean multi:boolean writeConcern:document})
query:查询条件,update:update对象和更新操作符类似set后面内容,upsert:可选,不
存在update记录,是否插入新的文档。multi:可选默认false,只更新找到的第一条记录
若为true,多条记录全部更新。writeConcern:抛出异常的级别
db.python.update({'title':'python'},{$set:{'title':'python爬虫'}},{multi:true})
save():通过传入的文档来代替已有的文档:db.collection.save(document,{writeCon
cern:document}) 参数:document:文档数据,writeConcern:可选抛出异常的级别
删除文档:remove() 删除文档:
db.collection.remove(query,{juseOne:boolean,writeConcern:document})
query:可选删除文档的条件,justOne:可选,true或1只删除一个文档
writeConcern:抛出异常的级别
Python操作MongoDB:
导入pymongo数据库模块:安装pymongo模块:pip install pymongo 导入:import pymongo
建立连接:pymongo模块使用MongoClient对象来描述一个数据库客户端:创建对象需要参数是:host,port,方式:
client=pymongo.MongoClient() client=pymongo.MongoClient('localhost',27017) client=pymongo.
MongoClient('moongodb://localhost:27017/')
获取数据库:一个MongoDB实例可以支持多个独立的数据库,使用时可以通过访问MongoClient的属性方式来访问
数据库:db=client.parpers 若数据库名导致属性方式访问不能用可以通过字典的方式访问数据库:db=client
['pa-pers']
获取一个集合:一个collection 指一组存在于MongoDB中的文档,获取collection方法和获取数据库的方法一致:
collection=db.books 或字典方式:collection=db['books'] collection和数据库都有惰性,上面所有命令实际
都没执行,直到第一个文档插入后,才会创建这就是为什么不插入文档,使用show dbs 查看不到之前创建的库
插入文档:数据在MongoDB中是以JSON类文件的形式保存起来的,在PyMongo中用字典来代表文档,使用insert()
方法来插入文档。文件被插入后若文件没有_id这个值,系统会自动添加一个到文件里(唯一)。insert()返回这个
文件的_id值。除了单个插入,也可以在insert()传入可迭代对象
查询文档:最常用:find_one(),返回一个查询文件,没有就返回None,支持对特定元素的匹配查询(给条件)。
collection.find_one({'_id':ObjectId('........')}),find()返回一个游标(Cursor)实例可便利
查询符合条件的数据条数:count(),collection.find().count()
修改文档:使用update()和save()来更新文档,collection.update({'author':"qiye"},{"$set":{"text","python book"}})
删除文档:remove() 语法:collection.remove({"author":"qiye"})
动态网站抓取:
Ajax:Ajax定义是异步的JavaScript和XML,是JavaScript异步加载技术。使用Ajax不必刷新整个页面。
DHTML:是Dynamic HTML简称,动态HTML,所谓动态只是HTML与CSS和客户端脚本语言的一种集合。
怎么抽取动态HTML有效的数据:一种直接从JavaScript中采集加载的数据,另一种是直接采集浏览器中已经加载好的数据
电影网站爬取(实例代码:P210)
PhantomJS:直接从浏览器中提取渲染好的HTML文档(在Ajax过多,请求参数还进行加密情况可以考虑:PhantomJS宣布暂停开发)
替换方案:
对于Firefox:Selenium+Headless Firefox:本地要有geckdriver,最好再配以下环境变量避免网页实例化webdriver就close()
对于Chrome:需要安装chromedriver
Selenium:官网:http://www.seleniumhq.org/ 下载:pip install Selenium==3.0.1 或者 http://pypi.python.org/pypi/selenium
下载源码,然后运行python setup.py install。selenium2.x调用高版本浏览器会出现兼容问题,3.x需要下载补丁
firefox:geckodriver,Chrome:chromedriver :补丁下载地址:http://www.seleniumhq.org/download/
下载之后解压到指定目录,然后配置环境变量
页面操作:页面交互与填充表单:第一步:初始化Firefox驱动,打开html文件。第二步:获取用户名和密码输入框等
第三步:使用send_keys方法输入用户名和密码,使用click方法模拟点击登录。若想清除输入框内容可以用click()
下拉框选择select元素:一种方式:轮流设置select选项卡内容。第二种方式:WebDriver中提供Select方法
(代码:P235)。
元素拖拽:先要找到源元素,和目的元素,然后使用ActionChains类可以实现
窗口和页面frame的切换:窗口可以switch_to_window方法:driver.switch_to_window('windowName')
页面:driver.switch_to_frame("frameName")
弹框处理:跳出了弹框可以使用:switch_to_alert获取弹框对象,从而进行关闭弹框,获取弹框信息等操作
历史记录:driver.forward() driver.back()
Cookie处理:get_cookies() 获取cookie,也可使用add_cookie()添加cookie信息
设置phantomJS请求头中User-Agent
等待:利用Ajax需要等待加载,Selenium有两种等待方式:一种显示等待,一种隐式等待
显示等待:条件触发式的等待方式:直到这个条件成立才会继续执行,可以设置超时时间。(代码:P238)
隐式等待:尝试发现某个元素时没能立即发现就等待固定长度的时间,设置隐式等待作用范围就是Webdriver
对象实例的整个生命周期。若时间过长可以修改代码:P239)
线程休眠:time.sleep(time):线程休眠延时的方法。
爬取去哪网:(实例代码:P239)
Web端协议分析:主要解决两个问题:一是网页登录POST分析,二是验证码问题
POST分析:登录才能爬取的网站属于深层次网页爬取。主要任务是完成登录获取Cookie,基本上是使用表单
提交POST请求。
隐藏表单:找到隐藏表单的位置,通过BeautifulSoup提取值,也可以直接使用正则表达式提取然后Requests
提交POST请求
加密数据分析:百度云登录为例(代码:P247)
第一部分:实际登录比较不同次登录时请求参数的变化情况(多次比较)
第二部分:比较变化参数产生的时间以确定是在哪块发生的变化。(代码:P249)
第三部分:找到所有可变参数出处后,然后模拟登录其中使用到了‘pyv8引擎’可以直接运行JavaScript代码
这样生成gid和callback的Javascript函数可以直接使用不用转换成Python语言(代码:P254)
源码下载地址:http://github.com/qiyeboy/baidulogin.git
验证码问题:对于爬虫验证码是天敌。
IP代理:当你使用同一个IP频繁访问网页时,网站服务器就极有可能将你判定为爬虫,此时会在网页中出现验证码,输入
正确才能正常访问。
一种解决方法:加大爬虫的延时,做到和人访问速率一样,不过这样效率会稍微低一些
另一解决方法:切换IP进行访问。
要解决的首先是用urllib2和Requests配置代理IP。其次是如何获取更多的代理IP:有以下几种方式:
VPN:VPN服务可以分配不同的网络线路,并可以自动更换IP,但需要钱适合商用。
IP代理池:厂商会将很多IP做成代理池提供API接口,很贵的。
ADSL宽带拨号:ADSL有一个特点,断开重新连接时分配的IP会有变换,由于要断开重连所以效率不高
可以使用Python实现拨号和断开,Windows提供了一个用于操作拨号的命令rasdial。(代码:P260)
IPProxyPool:(适合个人使用)开源项目代码地址:http://github.com/qiyeboy/IPProxyPool
原理:通过爬取各大IP代理网站的免费IP,将这些IP进行去重,检测代理有效性等操作,最后
存储到SQLite数据库种,并提供一个API接口,方便大家调用。(代码:P261)
开源项目使用:下载并解压缩,进入IPProxyPool目录运行:Python IPProxys.py
Cookie登录:每次登录都需要手动输入验证码,很繁琐不可取,但大部分网站登录后Cookie都会保持较长一段时间避免
用户繁琐输入账号和密码造成的不便。可以利用这个特性,再登录成功一次后可以将Cookie信息保存到本地,下
次直接使用Cookie登录(代码:P262)
传统验证码识别:上面Cookie登录失效后需要重复登录这个过程,同样很繁琐。若Python能自动识别验证码会省很多力
传统验证码不涉及含义的分析,只是识别内容识别相对简单。进行识别需要使用到tesseract-ocr。
python使用tesseract-oct识别验证码:需要模块:tesseract-oct,pytesseract 和 Pillow (安装P262)
Windows:tesseract-ocr:http://digi.bib.uni-mannheim.de/tesseract/
pytesseract:pip install pytesseract Pillow:pip install pillow
人工打码:当识别难度提高,程序很难保证较高的准确率,这时候就需要人工打码了。采用自动识别和人工识别的组合
有人工打码的平台,‘打码兔’,‘QQ超人打码’有提供各种语言的接入方式。是需要收费的。
滑动验证码:是一种基于行为的验证方式,很特别但也能突破。一种通用方法是使用selenium来进行处理。需要解决:
浏览器模拟鼠标拖动,计算图片缺口偏移量,模拟人类拖动轨迹。涉及到很多图像拼接方面的知识。还可以采
取多账号登录,保存cookie信息,组建cookie池的方法绕过。
滑动验证码识别参考:http://www.w2bc.com/article/170660
www>m>wap:www是PC网站,m和wap是移动端,智能手机一般用的是m站。因为wap站点简单可以优先爬取,伪装
不同平台需要修改User-Agent头信息,网站服务器会根据这个判断是从哪个平台发送的请求
终端协议分析:只要爬虫伪装成PC客户端或者移动客户,模拟请求方式就能爬取数据。这是终端协议分析的意义。
PC客户端抓包分析:PC抓包软件:Wireshark,Http Analyzer等。Wireshark比较重型,Http Analyzer专注HTTP/HTTPS
HTTP Analyzer简介:实时捕捉HTTP/HTTPS协议数据的工具,可以显示许多信息,也是分析诊断调试的开发工具。
下载连接:http://www.ieinspector.com/httpanalyzer/download.html 安装后启动,然后打开网页会抓取信息
爬取虾米音乐PC端:(实例代码:P269)
一些客户端的链接都是进行加密的,这样分析就会很困难,没有逆向PC客户端软件和分析算法的能力最好放弃。
APP抓包分析:策略是在电脑上安装一个Android模拟器,将应用安装到模拟器中,这时可以用Wireshark了。
Wireshark:最流行的网络分析工具,提供了网络和上层协议的各种信息。下载:https://www.wireshark.org/downloa
d.html
Android模拟器:天天模拟器,Bluestacks模拟器和Windroye模拟器
Scrapy爬虫框架:Scrapy使用Twisted这个异步网络库来处理网络通信,包含各种接口可以灵活完成各种需求
Scrapy引擎(Engine):引擎负责控制数据流在系统的所有组件中流动
调度器(Scheduler):调度器从引擎接收Request并将它们入队,以便之后提供
下载器(Downloader): 负责获取页面数据并提供给引擎,而后提供给Spider
Spider:Scrapy用户编写用于分析Response并提取Item或额外更进的URL类,每个Spider负责处理一个特定的网站
Item Pipeline:负责处理被Spider提取出来的Item
下载中间件(Downloader middlewares):引擎和下载器之间的特定钩子,处理Downloader传递给引擎的Response
Spider中间件(Spider middlewares): 引擎和Spider之间的特定钩子,处理Spider的输入和输出
详细过程(解释:P286)
安装Scrapy:
Windows:安装pywin32:地址:http://sourceforge.net/projects/pywin32/ 检验成功:import win32com
安装pyOpenSSL:地址:https://github.com/pyca/pyopenssl 下载后:python setup.py install 安装就好
安装lxml:pip install lxml 若提示Microsoft Visual C++ 库没装,可以http://www.microsoft.com/en-us/down
load/details.aspx?id=44266
安装Scrapy:pip install Scrapy
创建cnblogs项目:(实例开发:P288)
创建新项目:命令中切换到要存储的位置,运行命令:scrapy startproject cnblogSpider 即可创建
生成目录文件:scrapy.cfg:项目部署文件 cnblogSpider/: 项目的Python模块,可在此加入代码 cnblogSpider/ite
ms.py:项目中的Item文件 cnblogSpider/pipelines.py:项目中的Pipelines文件 cnlogSpider/setting.py
项目的配置文件 cnblogSpider/spiders/:放置Spider代码的目录
创建爬虫模块:爬虫模块放置在spiders文件夹中,爬虫模块时用于从单个网站或者多个网站爬取数据的类,其应包含
初始页面的URL,以及更进网页链接,分析页面内容和提取数据函数,创建一个Spider类需要继承scrapy.Spider
类并定义属性:name,start_url,parse()
启动spider:切换到根目录:执行:scrapy crawl cnblogs
选择器:爬虫模板完成后,仅仅拥有网页下载功能,后面需要进行网页数据提取。Scrapy有一套自己的提取机制,称为选择器
(selector)他们通过特定的XPath或者CSS表达式来选择HTML文件中的某个部分。Scrapy选择器构建于lxml库之上,也
可以脱离这套机制,使用BeautifulSoup包进行解析。
Selector的用法:有四个基本的方法:
xpath(query):传入XPath表达式query,返回表达式对应的所有节点
css(query):传入CSS表达式query,返回对应所有节点
extract():序列化该节点为Unicode字符串,并返回list列表
re(regex):根据传入的正则表达式对数据进行提取,返回Unicode字符串列表
HTML解析器的实现:(代码:P293)
命令行工具:Scrapy命令行功能:提供了两种类型的命令:一种必须在项目中运行,一种属于全局命令。(命令行:P296)
定义Item:从非结构性的数据源提取结构性数据。Scrapy中的Item来完成这部分功能。
翻页功能实现:提取当前页后提取下一页,这就需要翻页功能,本质上是构造Request并提交给Scrapy引擎的过程。(代码:P298)
构建Item Pipeline:数据持久化,Item Pipeline完成,Item被收集后会传递到Item Pipeline 会执行对Item的处理
功能:清理HTML数据,验证爬取的数据合法性,查重并丢弃,爬取结果保存到文件或者数据库。
定制Item Pipeline:(代码:P299)
激活Item Pipeline:目前是无法工作的,需要进行激活,启动一个Item Pipeline组建,必须将它的类添加到settings.py
中的ITEM_PIPELINES 变量中:ITEM_PIPELINES={‘cnblogSpider.pipelines.CnblogspiderPipeline’: 300}
激活完成后,将命令切换到项目目录下,执行scrap'y crawl cnblogs 命令 就可以将数据存储到papers.json文件中
内置数据存储:除了使用Item Pipeline 实现存储功能,Scrapy内置了一些简单的存储方式,生成一个带有爬取数据的输出
文件通常叫做输出(feed)支持多种序列化格式(介绍:P301)。
内置图片和文件下载方式:
Scrapy为下载Item中包含的文件提供了一个可以重用的Item Pipeline,有共同的方法和结构,称为MediePipeline 一般
会使用FilesPipeline 或者 ImagesPipeline
强化爬虫:Scrapy中调试方法,异常和控制运行状态等内容,可以帮我门更好的使用Scrapy编写爬虫
调试方法:有三种技术比较常用:Parse 命令,Scrapy shell 和 logging
Parse命令:可以在函数层上检查spider各个部分的效果(介绍:P309)
异常:Scrapy提供的异常及其用法:(代码:P311)
控制运行状态:Scrapy提供了内置的telnet终端以供检查控制Scrapy的运行进程。可以启用和关闭(代码:P313)