什么是爬虫:
爬虫 就是给网站发起请求,并从响应中提取需要的数据的自动化程序,在爬取数据的时候
- 爬虫的原理
如果要获取网络上的数据,我们要给爬虫一个网址(程序中通常叫URL),爬虫发送一个HTTP请求给目标网页的服务器,服务器返回数据给客户端(也就是我们的爬虫),爬虫在进行数据解析、存保等一系列操作
- 爬取数据的流程
爬虫可以节省我们的时间,比如我要获取豆瓣电影 Top250 榜单,如果不用爬虫,我们要先在浏览器上 输入豆瓣电影的 URL ,客户端(浏览器)通过解析查到豆瓣电影网页的服务器的 IP 地址,然后与它建 立连接,浏览器再创造一个 HTTP 请求发送给豆瓣电影的服务器,服务器收到请求之后,把 Top250 榜单从数据库中提出,封装成一个 HTTP 响应,然后将响应结果返回给浏器,浏览器显示响应内容, 我们看到数据。 爬虫也是根据这个流程,只不过改成了代码形式。
第一步:发起请求,获取响应结果
1.通过HTTP库,对目标站点进行请求,等同于模拟打开浏览器,输入网址,获得数据的整个过程。2.常用库: urllibx , urllib3x , requests,这些是常用的库文件3.服务器会返回请求的内容,一般为:HTML文件、二进制文件(视频,音频、图片) 、文档、 json字符串 等
第二步:解析内容
寻找自己需要的信息,就是利用正则表达式或者其他库提取目标信息常用库:re、beautifulsoup4 、这两个库可以实现从拿到的信息中提出所关注的信息
第三步:保存数据
将解析得到的数据持久化到文件或者数据库中
- HTTP请求报文
请求报文构成
HTTP请求 是产生于客户端的
HTTP请求格式包括三个部分
第一部分:请求行:
- 在请求行,树妖包括三个部分
- 请求方法,URL、协议版本
第二部分: 请求头:
- 在请求头中,主要是存向服务器端发请求的时候键值对
第三部分: 请求体:
请求体是发送给服务器请求时候,所携带的数据,比如你的账号密码
HTTP请求举例:
- 第一行是:请求行
- 第二 ~ 十一行是:请求头
- 第十二行是: 空白行
- 第十三行是: 请求体
请求行一定是http请求的第一行,包括下面几个部分
第一部分:请求方法
- GET:查询
- POST:添加
- DELETE:删除
- PUT:修改
- 注意:不区分大小写
第二部分:URL第三部分:协议
- HTTP1.1
- HTTP1.0
- HTTP0.9
另外,请注意
-
只有POST和PUT方法有请求体,原因是无论是添加,还是修改,需要将对应的数据发送到服务器 端,这样服务器端才能进行对应的修改操作
-
而GET和DELET方法是没有请求体的
- 请求头
对于请求头来说,我只要记住一个键值对就可以了,就是Content-Type这个,其他的,只要知道请求头里都是键值对就够了
Content-Type1. Content-Type:是用于描述请求体中的数据是什么类型的数据2. 必须严格区分大小写3. 对于GET 和 DELETE请求,不需要这个,因为这两个方法里没有请求体4. 只有当请求方法是POST和PUT的时候,这个参数才有用
Content-Type 请求体数据类型
1. text/html 表示HTML格式2. text/plain 表示纯文本格式3. text/jpeg 表示jpeg图片格式4. application/json:表示JSON格式数据5. application/x-www-form-urlencoded 表示默认的提交数据格式6. multipart/form-data 表示在表单中进行文件上传时使用的格式
- 请求体
请求体是位于空行之下的内容有的协议没有请求体,比如get delete请求的体的数据类型,受请求头的中的content-type的值影响
可以尝试用开发者工具抓包查看不同请求下,http请求报文的格式,包括
正常访问页面登录页面结果中就会发现,有的数据是有请全体的,但是有的是没有的
- HTTP响应报文
- 响应报文的构成
在http响应这里,我主要学习两个东西
- http响应状态码
- http的响应体
httpd响应,一定是服务器端产生的
只有在服务器端收到客户端的请求以后,服务器端才会产生http响应报文
http的响应是也包括三个部分的
第一部分:响应行,也称之为状态行,包括了 协议版本、状态码、状态码描述第二部分:响应头,我们只需要知道格式是k-v格式,但是我们不需要记任何具体的内容空行第四部分:响应体,响应体是服务器端返回给客户端的数据
注意:
GET和DELETE的请求报文中,是没有请求体的但是对于响应报文来说,所有的响应报文,都是有响应体的。**
案例:找出响应行、响应头、响应体
HTTP/1.1 200 OK
Data: Fri, 22 Oct 2022 06:07:02 GMT
Content-Type: text/htlm; charset=UTF-8
<html>
<head><head>
<body>....</body>
</html>
Content-Type的作用和请求头中的作用是一样的,都是用于描述体中的内容格式
- 相应行
位置是响应数据包的第一行作用是描述服务器的处理结果内容构成:
- 协议版本号
- 状态码
- 消息短语
状态码有三个数字构成
1xx:提示信息2xx:成功3xx:重定向4xx:客户的错误5xx:服务器端错误
- 响应头
位于响应行之下,空行之上的部分数据的组织格式都是K-V对
- 响应体
位于空行之下几乎所有的响应报文,都有相应体
- 不管是查询,还是删除,虽然请求报文中没有请求体,但是无论这个数据有没有,都必须给个回 应,所以说,一般都是有响应体的。
- 只有极端的情况,才会没有响应体,这个我们一般系接触不到
发送请求的方法
urllib 发请求
自带模块在发送请求的时候,可以urllib模块
方法名:request.urlopen()
案例:向百度发送请求
# coding = utf-8
import time
import sys
from urllib import request
# 需要注意协议类型
url = "http://www.baidu.com"
# 获取相应的对象
res = request.urlopen(url)
# 获取响应头
print(f"响应头是:{res.info}")
# 获取状态码
print(f"状态码是:{res.getcode()}")
# 获取主机地址
print(f"主机地址是:{res.geturl()}")
# 获取响应体中数据
# 获取返回的字节码格式内容
# 如如果返回的字节码内容多的话,会直接打印乱码
html_comtent = res.read()
# print(html_comtent)
# 对字节码内容进行解码
print(html_comtent.decode("utf-8"))
注意,这种爬取数据的方式,在很多网站是被禁止的
比如在爬取 大众点评的时候,就会失败,一种简单的应对方法就是在发送请求的时候,伪造一个浏 览器信息,比如
具体如下:
# coding = utf-8
import time
import sys
from urllib import request
# 需要注意协议类型
url = "http://www.baidu.com"
# 定义头信息
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
# 用Request发送请求
req = request.Request(url, headers=header)
# 获取相应的对象
res = request.urlopen(url)
# 获取响应头
print(f"响应头是:{res.info}")
# 获取状态码
print(f"状态码是:{res.getcode()}")
# 获取主机地址
print(f"主机地址是:{res.geturl()}")
# 获取返回的字节码格式内容
# 如如果返回的字节码内容多的话,会直接打印乱码
html_comtent = res.read()
# print(html_comtent)
# 对字节码内容进行解码
print(html_comtent.decode("utf-8"))
-
requests 发请求
-
request库简介这个request库,他的作用其实也就是发送http请求,需要有请求行、请求头、请求体
安装requests库
方法1:pip安装
安装的命令
- pip install requests -i https://pypi.douban.com/simple/
检查安装结果的
- pip list
- pip show 库名
方法2:pycharm中进行安装
request库语法
首先要知道,所谓的库,其实是一个简称,全称应该是函数库,就是这是一个仓库,在仓库里面放的 是一个一个的函数因此,我们是使用库,其实是调用这个库的函数。这是原理。
Request库中的http请求语法格式
思考一下:上面写了,请求体有表单格式的,用data表示;也可以是json格式的,用json表示json格
式的请求体。问题:这两个参数能同时用码?
- 肯定不可以
- 请求体只能是一种数据格式
补充一点:关于字符串的引号的问题
在python中,表示字符串的时候,可以用双引号,也可以用单引号,都没问题。但是为了和其他的编程语言兼容,因此建议用双引号
-
入门的案例
import requests
# 定义目标url
dest_url = "https://www.baidu.com"
# 向url发送请求
rest = requests.get(dest_url)
# 获取状态码
print(rest.status_code)
# 获取响应体中的数据
print(rest.text)
可以将显示结果换行显示
-
获取返回数据方法
-
【都是从resp中获取指定数据的】
1. 获取 URL:resp.url2. 获取 响应状态码:resp.status_code3. 获取 Cookie:resp.cookies4. 获取 响应头:resp.headers5. 获取 响应体:
- 文本格式:resp.text
- json格式:resp.json()
- 注意:不是所有的结果都能转换成json格式数据。如果是将不能转成为json格式的数据进行 了转换,那么就会报错,报错信息如下:JSONDecodeError,下面最后的一个案例,就会 报这个错
import requests
# 定义目标url地址
dest_url = "https://www.baidu.com"
# 向目标发送http请求
res = requests.get(url=dest_url)
# 输出结果信息
print(f"响应状态码:{res.status_code}")
print(f"请求的url:{res.url}")
print(f"获取Cookie:{res.cookies}")
print(f"获取编码类型:{res.encoding}")
# print(f"获取响应头:{res.headers}")
print(f"获取响应体:{res.text}")
需要注意的点
1. ISO-8859-1编码是单字节编码,向下兼容ASCII1. Content-type:text/html 就是表示了这个页面文件的格式是文本文件2. 如果在Content-type中使用了关键字 Charset=XXX,那么编码就是这个指定的;人工没有 指定的话,那么编码就用ISO-8859-13. 如果在header中没有出现 Content-type 这个关键字的话,那么编码就是utf-8
现在的编码是8859-1,所以在显示中文的时候,一定有乱码,如下
import requests
# 定义目标url地址
dest_url = "https://www.baidu.com"
# 向目标发送http请求
res = requests.get(url=dest_url)
# 输出结果信息
print(f"响应状态码:{res.status_code}")
print(f"请求的url:{res.url}")
print(f"获取Cookie:{res.cookies}")
print(f"获取编码类型:{res.encoding}")
# print(f"获取响应头:{res.headers}")
# 将收到的内容编码,用utf-8进行编码,避免出现中文乱码
res.encoding = "utf-8"
print(f"获取响应体:{res.text}")