爬虫实战4—多线程与多进程爬虫
文章说明:本文是在学习一个网络爬虫课程时所做笔记,文章如有不对的地方,欢迎指出,积极讨论。
一、表单及登录
登录的核心是为了获得cookie,登录成功后,header会有设置cookie的相关信息,此时我们需要把服务器返回的cookie信息,写入到我们后续请求的header的cookie里。
(一)HTML提交数据:
(1)form表单
由浏览器实现post方法
表单类型(主要):form-data和x-www-form-urlencoded
(2)ajax请求
用JavaScript对网页进行处理,一般以JSON方式提交数据
(二)获取并设置Cookie
二、多线程及语言分析对比
(一)多线程爬虫
进程(process):是指正在运行的程序的实例。
第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
运行中的进程可能具有以下三种基本状态:
1)就绪状态(Ready):进程已获得除处理器外的所需资源,等待分配处理器资源;只要分配了处理器进程就可执行。
2)运行状态(Running):进程占用处理器资源。
3)阻塞状态(Blocked):由于进程等待某种条件(如I/O操作或进程同步),在条件满足之前无法继续执行。该事件发生前即使把处理器资源分配给该进程,也无法执行。
第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时OS执行之),它才能成为一个活动的实体,我们称其为进程。
线程(thread):有时被称为轻量级进程(LightWeightProcess,LWP),是程序执行流的最小单元。一个标准的线程由线程ID、当前指令指针(PC)、寄存器集合(registers)和堆栈组成。线程是进程中的一个实体,是被系统独立调度和分派的基本单位。
在单个程序中同时运行多个线程完成不同的工作,称为多线程。
把进程作为分配资源的基本单位,把线程作为独立运行和独立调度的基本单位。
意外:当遇到网页登录后,返回302跳转的情况下,urllib的response会丢失Set-Cookie信息,导致登录不成功,因此我们需要一个通用的能处理Cookie的工具(CookieJar)来:
1.自动处理Set-Cookie请求
2.自动处理过期的Cookie
3.自动在对应域下发送特殊的cookie
三、多线程爬虫(更轻,更快,不太可靠)
(一)多线程的复杂性
1.资源、数据的安全性:锁保护
2.原子性:数据操作是天然互斥的
3.同步等待:wait()notify() notifyAll()
4.死锁:多个线程对资源互锁,造成死锁
5.容灾:任何线程出现错误,整个进程都会停止
(二)Python线程
1.支持多线程(JavaScript、PHP不支持多线程)
2.Python线程直接映射到native线程
3.GIL(globalinterpretor lock):对于多核的利用能力有限
(三)实现一个多线程爬虫
1.创建一个线程池threads=[]
2.确认URL队列线程安全Queue Deque
3.从队列取出uURL,分配一个线程开始爬取pop()/get() threading.Thread
4.如果线程池满了,循环等待,直到有线程结束 t.is_alive()
5.从线程池移除已经完成下载的线程threads.remove(t)
6.如果当前级别的URL已经遍历完成,t.join()函数等待所有现场结束,然后开始下一级别的爬取
使用threading,做了封装、容灾等,使用更安全
而非thread,更底层,安全性比较低
(四)pythonMySQL connector
使用MySQLConnectionPool来管理多线程下的mysql数据库连接。
(五)多线程爬虫评价:
优势:
1)有效利用CPU时间
2)极大减小下载出错、阻塞对抓取速度的影响,整体上提高下载的速度
3)对于没有反爬虫限制的网站,下载速度可以多倍增加
局限性:
1)对于有反爬的网站,速度提升有限
2)提高了复杂度,对编码要求更高
3)线程越多,每个线程获得的时间就越少,同时线程切换更频繁也带来额外开销
4)线程之间资源竞争更激烈
线程与进程
四、多进程爬虫(更重,更慢,可靠)
多进程爬虫可以认为是分布式爬虫的基础,在单机上也可以用。因为一般大型的网站的服务器都是采用分布式部署的,可以采用多进程同时在不同的服务器器上进行爬取。
(一)进程间通信
主要是socket:可以标准化,可以用于多机
socket:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
(二)Android进程间通信AIDL(AndroidInterface Difinition Language,Android接口定义语言)
Android系统中的进程不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。
Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现
(三)创建多进程爬虫
(1)采用c/s模式:运行速度快;扩展方便。
(2)采用DB模式:开发便捷,DB本身具备读写保护及支持IPC;只需写一个爬虫程序。