爬虫·崔庆才网课笔记第一章(章节序号以教材为准)

Chapter 1 爬虫基础

1.1HTTP基本原理

1 URI和URL

Uniform Resource Identifier URI,统一资源标志符
Universal Resource Locator URL,统一资源定位符
URL是URI的子集
URI的另一个子集为URN,Universal Resource Name,为资源命名但不定位资源

https://github.com/favicon.ico
https访问协议、访问路径(根目录)和资源名称favicon.ico
.ico图标文件在这里插入图片描述

2.HTTP和HTTPS

超文本(Hypertext):网页源代码HTML,浏览器解析得到网页
超文本传输协议(HTTP):保证高效而准确地传送超文本文档,目前广泛使用HTTP1.1版本。ftp,sftp,smb均为协议类型。
HTTPS:在HTTP加入SSL(Secure Socket Layer)层加密。
作用:

  1. 建立信息安全通道,保证数据传输安全。
  2. 确认网站真实性,凡使用HTTPS的网站,可点击浏览器地址栏的锁头标志查看网站认证的真实信息,可通过CA机构颁发的安全签章查询。

3.HTTP请求过程

Request请求,;Response响应。
Network面板:

  • Type列:请求的文档类型,document表示HTML文档。
  • Initiator:请求源。
  • Waterfall:网络请求的可视化瀑布流。

4.请求

请求包含四部分:请求方法、请求网址、请求头、请求体。

  • 请求方法:GET、POST。
    浏览器直接输入URL回车,发起GET请求。数据显示于URL,最多1024字节。
    POST:点击“登录”,发起POST请求,数据以表单的形式传输,而不体现在URL。数据包含在请求体,隐示。没有大小限制。

  • 请求头包含浏览器标识、cookie、Host。
    Host:指定请求资源的主机IP和端口号,其内容为请求URL的原始服务器或网关的位置。从HTTP1.1版本起,请求必须包含此内容。
    Cookies:标识对应服务器的会话。在请求头加上Cookies,将其发送给服务器识别出登录状态,返回登录权限可见的内容。
    Content-Type:互联网媒体类型
    在这里插入图片描述

  • 请求体承载POST请求的表单数据,GET请求为空。

5.响应

  • 响应状态码

  • 响应头
    Expires:指定响应的过期时间,使代理服务器或浏览器将加载的内容更新到缓存。

  • 响应体
    请求网页,响应体为HTML代码;请求图片,响应体为二进制图片。

1.2 Web网页基础

1.网页的组成

HTML(骨架)、CSS(皮肤)和JavaScript(血肉)

  • HTML,布局标签div嵌套
  • CSS(Cascading Style Sheets):层叠样式表
    -层叠:样式冲突时依据层叠顺序处理。样式:网页文字大小等格式。在这里插入图片描述

HTML用link标签引入写好的.css文件。

  • Javascript,脚本语言,实时动态交互,使用户与信息之间不仅是浏览与显示。扩展名.js

2.网页的结构

在这里插入图片描述

  • head:定义页面的配置和引用。包含:
    title:网页的标题,出现在网页选项卡而非正文中。
  • body:正文显示内容。包含:
    div:网页的区块。
    h2:二级标题。
    p:段落。

3.节点树及节点间的关系

标签定义的内容都是节点。DOM(Document Object Model)文档对象模型。中立于平台与语言的接口,允许程序和脚本动态访问和更新文档的内容、结构和样式。

  • HTML文档中的所有内容都是节点:
  • 整个文档是一个文档节点;
  • 每个HTML元素是元素节点; HTML元素内的文本是文本节点;
  • 每个HTML属性是属性节点
  • 注释是注释节点
    在这里插入图片描述

4.选择器

<div id="container">

表示为#container,#表示选择id,其后为id名称。

.wrapper,.表示选择class,其后为class名称。
标签名,h2
#container .wrapper p 先选择id为container的节点,再选中内部的class为wrapper的节点,最后再选中其内部的p节点。

div#container .wrapper p.text
不加空格为并列关系。

1.3 爬虫的基本原理

1.爬虫概述

  • 获取网页。构造请求发送给服务器,接收到响应并解析。
  • 提取信息。正则表达式。beautiful Soup、pyquery、lxml,分别根据网页节点属性、CSS选择器和XPath提取网页信息。
  • 保存数据。保存为TXT、JSON文本;或数据库MySQL、MongoDB或远程服务器SFTP。

2.能爬怎样的数据

页面返回HTML代码,或API接口返回JSON字符串。

3.JavaScript渲染的页面

原始的HTML代码为空壳。分析后台Ajax接口,或使用Selenium、Splash等库模拟JavaScript的渲染。

1.4 Session和Cookie

1. 静态网页。动态网页

动态解析URL的变化,实现登录和注册。

2.无状态HTTP

HTTP协议对事务处理没有记忆能力。
浏览器端:Cookies。服务端:Session(会话)。
会话Cookie和持久Cookie

5.常见误区

关闭浏览器不会导致Session被删,服务器为Session设置一个失效时间。

1.6 多线程和多进程的基本原理

1.多线程

进程:可以独立运行的程序单位。进程是线程的集合。
线程:操作系统进行运算调度的最小单位,是进程的最小运行单元。

2.并发(concurrency)和并行(parallel)

并发:同一时刻仅一条指令执行,但多个线程的对应指令被快速轮换执行。
并行:同一时刻多条指令在多个处理器同时执行。

3.多线程适用场景

一个程序进程中,某些操作需要等待,如数据库查询结果的返回、网页结果的响应。IO密集型任务——爬虫。
CPU密集型任务,开启多线程始终忙于计算。
threading模块实现多线程。

def target(second):
	print(f'{threading.current_thread().name} is running')
	print(f'{threading.current_thread().name} sleep {second}s')
	time.sleep(second)
	print(f'{threading.current_thread().name}is ended')

for i in [1,5]:
	t=threading.Thread(target=target,args=[i])
	t.start()
	#t.join()%等待该子线程t运行结束才执行接下来的语句。
print(f'{threading.current_thread().name}is ended')#主线程	

结果:
主线程退出先于子线程退出。
join([time]):意味着等到队列为空,再执行别的操作。可选项为超时发生。

setDaemon:守护线程(后台线程)。表示该线程是不重要的,进程退出时不需要等待这个线程执行完成。这样做的意义在于:避免子线程无限死循环,导致退不出程序。
若调用join方法,无论是否为守护线程,会等待该线程执行完毕。

多个线程同时对某个数据读取或修改,出现不可预料的结果。GIL:Global Interpreter Lock,全局解释器锁。加锁的线程把锁释放,其他线程才能继续加锁并对数据做修改,完毕后释放锁,避免多个线程不会同时读取修改同一个数据,所以多线程不能发挥多核优势。

class MyThread(threading.Thread):
	def __init__(self):
		threading.Thread.__init__(self)

	def run(self):
		global count
		lock.acquire()
		temp=count+1
		time.sleep(0.001)
		count=temp
		lock.release()

lock=threading.Lock()

(联想,数值模拟斯托克斯参量,A方法调用B方法最近一次迭代的值,A的结果错误地与B接近)

多进程multiprocessing,每个进程都有属于自己的GIL,多核处理器中多进程的运行不受GIL影响。有优势。但由于进程是资源分配调度的一个独立单位,各进程间全局变量无法共享。

API调用

Process([group[,target[,name[,args[,kwargs]]]]])

target:传入方法名;
args:位置参数元组
若target的函数有两个参数m,n,则args传入[m,n]
kwargs:表示调用对象的字典。
name:为进程取名。
group:分组

def process(index):
	time.sleep(index)
	print(f'Process:{index}')

if __name__=='__main__':
	for i in range(5):
		p=multiprocessing.Process(target=process,args=(i,)) #(i,)逗号表示元组
		p.start()
	print(f'{multiprocessing.cpu_count()}')
	for p in multiprocessing.active_children():
		print(f'{p.name} id:{p.pid}')
	print('Process Ended')

cpu_count方法返回当前机器CPU的核心数量
active_children方法返回当前还在运行的所有进程

结果:
Process Ended
Process:1
Process:2
Process:3
……
先Process Ended,再结束睡眠。

继承Process类

class MyProcess(Process):
	def __init__(self,loop):
		Process.__init__(self)
		self.loop=loop

	def run(self):
		for count in range(self.loop):
			time.sleep(1)
			print(f'{self.pid} LoopCount:{count}')

if __name__=='__main__':
	for i in range(2,5):
		p=MyProcess(i)
		p.start()

结果(竖着读结果):
(self.loop=2) 0 1
(self.loop=3) 0 1 2
(self.loop=4) 0 1 2 3

if __name__=='__main__':
	for i in range(2,5):
		p=MyProcess(i)
		p.daemon=True#子进程为守护进程,避免孤立子进程的执行
		p.start()
		p.join()

终止进程terminate方法;is_alive方法判断进程是否仍在运行

if __name__ == '__main__':
	p=multiprocessiing.Process(target=process)
	print('Before:',p,p.is_alive())

	p.start()
	print('During:',p,p.is_alive())

	p.terminate()
	print('Terminate:',p,p.is_alive())

	p.join()
	print('Joined:',p,p.is_alive())

terminate()之后仍为alive,join()之后才为stopped。terminate无法立即终止,须用join令主程序等待其停止。

class MyProcess(Process):
	def __init__(self,loop,lock):
		Process.__init__(self)
		self.loop=loop
		self.lock=lock
		
	def run(self):
		for count in range(self.loop):
			time.sleep(0.1)
			#self.lock.acquire()
			print(f'{self.pid} LoopCount:{count}')
			#self.lock.release()

if __name__=='__main__'
	lock=Lock()
	for i in range(10,15):
		p.MyProcess(i,lock)
		p.start()

结果:有些打印输出未换行
取消代码的两行注释,进程互斥锁,结果每句打印均换行。

Semaphore信号量:控制临界资源的数量,实现多个进程同时访问共享资源,限制进程的并发量。
Queue队列:让进程共享数据。如果queue换为全局list,由于进程间的资源不共享,在A进程改变list,B不能获取该list的状态。
duplex管道:实现进程间通信。单向half-duplex一个进程发消息一个接收;双向duplex互相收发。单工双工。pipe默认为双向管道。

进程池Pool:请求会等待直到池中有进程结束,才会创建新的进程来执行它。
map方法:

pool.map(scrape,urls)

scrape只能传入单个url,map使urls批量被调用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值