多线程爬虫
多线程的复杂性
1.资源、数据的安全性:锁保护
2.原子性:数据操作是天然互斥的
3.同步等待:wait()、notify()、notifyAll() #notify,通知
4.死锁:多个线程对资源互锁,造成死锁
5.容灾:任何线程出现错误,整个进程都会停止
多线程的优势
1.内存空间共享,信息数据交换效率高
2.提高CPU的使用效率
3.开发便捷
4.轻,创建、销毁的开销小
Python线程
支持多线程(JavaScript PHP 不支持多线程)
Python线程直接映射到native线程(Java1.4的Java线程是JVM实现的,共同运行在一个native thread) #native,本地的 thread,线
GIL:对于多核的利用能力有限
实现一个多线程爬虫
1.创建一个线程池threads=[ ]
2.确认url队列线程安全 Queue Deque
3.从队列取出url,分配一个线程开始爬取pop()/get()threading.Thread
4.如果线程池满了,循环等待,直到有线程结束t.is_alive()
5.从线程池移除已经完成下载的线程threads.remove(t)
6.如果当前级别的url已经遍历完成,t.join()函数等待所有现场结束,然后开始下一级别的爬取
多线程爬虫评价
优势:1.有效利用CPU时间
2.极大减少下载出错、阻塞对抓取速度的影响,整体上提高下载速度
3.对于没有反爬虫限制的网站,下载速度可以多倍增加
局限性:1.对于有反爬虫的网站,速度提升有限
2.提高了复杂度,反编码要求更高
3.线程越多,每个线程获得的时间就越少,同时线程切换更频繁也带来额外开销
4.线程之间资源竞争更激烈
多进程爬虫
线程与进程
多进程爬虫评估:
目的:1.控制线程数量
2.对线程进行隔离,减少资源竞争
3.某些环境下,在单机上利用多个IP来伪装
局限性:1.不能突破网络瓶颈
2.单机的IP的情况下,变得没有意义
3.数据交换的代价更大
进程间通信
管道(PIPE)
信号(Signal):复杂
消息队列:Posix及System V
共享内存:速度最快,需要结合信号量达到进程间同步及互斥
信号量:用于数据同步
Socket:可以标准化,可以用于多机
Android进程间通信Binder
Android进程间通信AIDL
创建多进程爬虫
solution A-C/S模式 #solution,解决方案
1.一个服务进程,入队及出队URL,入队需检查是否已经下载
2.监控目前的爬取状态、进度
3.多个爬取进程,从服务进程获取URL,并将新的URL返回给服务进程
4.使用Socket来做IPC
solution B-数据库模式
1.使用数据库来读写爬取列表
2.多个爬取进程,URL的获取与增加都通过数据库操作
C/S vs 数据库
CS优势:1.运行速度快,添加、修改、查询都是内存的BIT位操作
2.扩展方便。例如动态URL队列重拍
数据库:1.开发便捷,数据库天生具备读写保护及支持IPC
2.只需要写一个爬虫程序
创建MySQL数据库表
数据库创建
Python MySQL connector #connector,连接器
使用MySQLConnectionPool来管理多线程下的mysql数据库连接
mysql.connector.pooling.MySQLConnectionPool
self.cnxpool.get_connection()
_init_类实例的时候自动检查和创建数据库及表
Cursor类:cursor=con.cursor(dictionary=Ture) #cursor,光标
SELECT...FOR UPDATE加读锁,避免多个进程取出同一个url
cursor.commit()支持事物,默认关闭了autocommit因此需要提交 #commit提交