一、Session与Cookies
1.静态网页和动态网页
静态网页:
但是存在很大的缺陷,如:可维护性差,不能根据URL灵活多变地展示内容等
因此,动态网页应运而生,可以动态解析URL中参数的变化,关联数据库并动态呈现不同的页面内容,非常灵活多变。
现在遇到的大多数网站都是动态网站,不再是一个简单的HTML,可能是由JSP、 PHP、 Python等语言编写的,其功能比静态网页强大和丰富太多,动态网页还可以实现用户登录和注册的功能
2.无状态HTTP
HTTP特点之一:无状态,指的是HTTP协议对事务处理没有记忆能力,也就是说服务器不知道客户端是什么状态。一位置如果后续需要处理前面的信息,则必须重新上传,这也导致了需要额外传递一些前面的重复请求,才能获取后续响应。
3.Session、Cookie
Session本身的含义是指有始有终的一系列动作 / 消息
比如打电话时,从拿起电话拨号到挂断电话这中间的一系列过程可以称为一个Session,在Web中,Session对象用来存储特定用户Session所需的属性及配置信息
Cookies指某些网站为了辨别用户身份、进行Session跟踪而存储在用户本地终端上的数据。
当客户端第一次请求服务器时,会返回一个响应头中带有Set-Cookie字段的响应给客户端,用来标记一个用户,客户端浏览器会把Cookies保存起来
当浏览器下一次再请求该网站时,浏览器会把此Cookies放到请求头一起提交给服务器,服务器检查该Cookies可找到对应的Session,然后判断用户状态。
二者共同协作实现了登录Session控制
表面意思来说:
会话Cookie就是把Cookie放在浏览器内存里,浏览器关闭后Cookie就失效。
持久Cookie则会保存到客户端的硬盘中,下次还可以继续使用,用于长久保存用户登录状态
严格来说:
没有会话Cookie和持久Cookie之分
只是由Cookie的Max Age或Expires字段决定了过期的时间
4.常见误区
1.在谈论Session机制时
常听到一种误解——只要关闭浏览器,Session就消失了
对Session来说除非程序通知服务器删除一个Session,否则服务器会一直保留,比如程序一般都是我们做注销操作时才能删除Session
2.当关闭浏览器时
浏览器不会主动在关闭之前通知服务器它将要关闭
所以服务器根本不会有机会知道浏览器已经关闭
3.由于关闭浏览器不会导致Session被删除
这就需要服务器为Session设置一个失效时间
当距离客户端上一次使用Session的时间超过这个失效时间时
服务器就可以认为客户端已经停止了活动
才会把Session删除以节省时间
二、多线程基本原理
1.多线程含义
进程可以理解是一个可以独立运行的程序单位
为什么可以做到同时运行这么多的任务??
任务对应着线程的执行
进程由一个或多个线程构成
线程是操作系统进行运算调度的最小单位,是进程中的一个最小运行单元
2.并发和并行
3.多进程适用场景
在一个程序进程中,有些操作室比较耗时或者需要等待的,如:
· 等待数据库的查询结果的返回
· 等待网页结果的响应
网络爬虫就是一个典型的例子:
爬虫在向服务器发起请求之后,有一段时间必须要等待服务器的响应返回,这种任务就属于IO密集型任务
不是所有的任务都是IO密集型任务,有一种任务叫做计算密集型任务,也可以称之为CPU密集型任务。就是任务的运行一直需要处理器的参与
4.Python实现多线程
在Python中,实现多线程的模块叫做threading,是Python自带的模块。
加锁保护是什么意思:
5.多进程的含义
进程是具有一个独立功能的程序关于某个数据集合上的一个运行活动,是系统进行资源分配和调度的一个独立单位
多进程就是启用多个进程同时运行
由于进程中GIL的存在,多线程并不能很好的发挥优势,一个进程中的多个线程,同一时刻只能有一个线程运行
对于多进程而言: 每个进程都有属于自己的GIL
多进程能更好的发挥多核的优势
能用多进程就用多进程
6.多进程的实现
直接使用Process类:
multprocessing提供了比较有用的方法:通过cpu_count方法来获取当前机器CPU的核心数量、通过active_children方法获取当前还在运行的所有进程
继承Process类:创建进程的方式不止一种,也可以像线程Thread一样通过继承创建进程,基本操作在子类的run方法中实现即可
守护进程:如果一个进程被设置为守护进程,父进程结束子进程会终止
终止进程:终止进程可以通过terminate方法来种植某个子进程,还可以通过is_alive方法来判断进程是否还在运行
7.信号量
信号量是进程同步过程中一个比较重要的角色,可以控制临界资源的数量,实现多个进程同时访问共享资源,限制进程的并发量,可以用multiprocessing库中的Semaphore来实现信号量
8.管道
可以理解为两个进程之间的通信通道
可以是单向的,即half-duplex:一个进程负责发消息,另一个进程负责收消息,也可以是双向的duplex,即互相收发消息
默认声明Pipe对象是双向管道如果要创建单向,在初始化时传入deplex参数为False
三、requests库的基本使用
抓取二进制数据:图片、视频、音频这些文件本质上都是由二进制码组成,想要抓取,就要拿到二进制数据
Session维持:在requests中,如果直接利用get或post等方法的确可以做到模拟网页鹅蛋请求,但实际上是相当于不同的Session,也相当于用两个浏览器打开了不同的页面
SSL证书验证:现在很多网站都要求使用HTTPS协议,但是有些网站可能没有设置好HTTPS证书,或者网站的HTTPS证书不被CA机构认可,这时这些网站可能就会出现SSL证书错误的问题
如果我们一定要爬取这个网站怎么办?
可以使用verify参数控制是否验证证书,如果将其设置为False
在请求时就不会再验证证书是否有效
代理设置:某些网站在测试的时候请求几次,能正常获取内容。但是对于大规模且频繁的请求,网站可能会弹出验证码或者跳转到登录认证页面,更有甚者可能会直接封禁客户端的IP,导致一定时间段内无法访问,为了防止这种情况发生,需要设置代理来解决这个问题,这就需要用到proxies参数
四、PyQuery的使用
PyQuery是Python的第三方库,可以借助pip3安装
pip install pyquery
1.初始化
解析HTML文本时,需要将其初始化为一个pyquery对象
直接传入字符串 // 直接把HTML的内容当做参数
传入URL // 传递网页的URL,指定参数为url即可
传入文件名 // 传递本地文件名,参数指定为filename即可
等等
2.遍历
pyquery的选择结果:
可能是多个节点,可能是单个节点,都是pyquery类型,并没有返回列表
子节点:查找子节点用find方法,传入参数是CSS选择器
find 的查找范围是节点的所有子孙节点,如果只想查找子节点,可以用children方法
父节点:用parent方法获取某个节点的父节点,用parent方法获取某个祖先节点
筛选某个祖先节点,则向parents方法传入CSS选择器
兄弟节点:用siblings方法获取兄弟节点
筛选某个兄弟节点,依然可以用siblings方法传入CSS选择器
3.获取信息
最终目的是提取节点所包含的信息
1.获取属性
调用attr方法获取属性
调用attr属性获取属性值
2.获取文本
调用text方法获取内部文本
想获取节点内部的HTML文本,就要用html方法
4.节点操作
pyquery提供了一系列方法来对节点进行动态修改,比如:
为某个节点添加一个class
移除某个节点等
除了操作 class 属性外,还可以用 attr 方法对属性进行操作,还可以用 text 和 html 方法来改变节点内部的内容,用 remove 方法进行移除,还有很多其他节点操作方法,比如 append、 empty 和 prepend 等方法
五、MongoDB的使用
安装MongoDB并启动其服务
安装Python的PyMongo库
pip install pymongo
1.连接MongoDB
需要使用PyMongo库里面的MongoClient
import pymongo
client = pymongo.MongoClient( host='localhost', port=27017)
2.指定数据库
MongoDB中可以建立多个数据库,需要指定操作其中一个数据库
db = client.test
MongoDB的每个数据库又包含许多集合(collection),类似于关系型数据库中的表
collection = db.students
对students这个集合新建一条学生数据
student = {
'id' : '20170101',
'name' : 'Jordan',
'age' : 20,
'gender' : 'male'
}
调用collection的insert方法即可插入数据
result = collection.insert(student)
print(result)
目前官方推荐使用insert_one和insert_many方法来插入单条记录和多条记录
3.查询
利用find_one或find方法进行查询
find_one查询得到的是单个结果
find则返回一个生成器对象
可以根据ObjectId来查询,此时需要调用bson库里面的objectid
from bson.objectid import ObjectId
result = collection.find_one({'_id': objectId('593278c115c2602667ec6bae)})
print(result)