爬虫-基本入门
爬虫概念
-
什么是爬虫?
- 程序猿:写程序,然后去互联网上抓取数据的过程
- 互联网:网,有好多的a链接组成的,网的节点就是每一个a链接 url(统一资源定位符)
-
哪些语言可以实现爬虫?
- php,可以做,号称世界上最优美的语言,多进程、多线程支持的不好
- java,也可以做爬虫,人家做的很好,最主要的竞争对手,代码臃肿,重构成本大
- c、c++,是你能力的体现,不是良好的选择
- python,世界上最美丽的语言,语法简单、代码优美,学习成本低,支持的模块多,非常强大的框架 scrapy
-
通用爬虫、聚焦爬虫
- 通用爬虫:百度、360、搜狐、谷歌、必应…
- 原理:
- 抓取网页
- 采集数据
- 数据处理
- 提供检索服务
- 爬虫:baiduspider
- 通用爬虫如何抓取新网站?
- 主动提交url
- 设置友情链接
- 百度会和DNS服务商合作,抓取新网站
- 检索排名
- 竞价排名
- 根据pagerank值、访问量、点击量(SEO)
- robots.txt
- 如果不想让百度爬取,可以编写robots.txt,这个协议是口头上的协议
- 自己写的爬虫程序不需要遵从
- 聚焦爬虫
- 根据特定的需求,抓取指定的数据
- 思路?
- 代替浏览器上网。网页的特点:
- 网页都有自己唯一的url
- 网页内容都是html结构的
- 使用的都是http、https协议
- 代替浏览器上网。网页的特点:
- 爬取步骤:
- 给一个url
- 写程序,模拟浏览器访问url
- 解析内容,提取数据
-
环境
- windows环境、linux环境
- Python3.6 64位的
- sublime、pycharm、vscode
-
学习内容
- 使用到的库:urllib、requests、bs4…
- 解析网页内容的知识:正则表达式、bs4、xpath、jsonpath
- 涉及到动态html:selenium+phantomjs、chromeheadless
- scrapy框架:高性能框架使用
- scrapy-redis组件:redis,分布式爬虫
- 涉及到爬虫-反爬虫-反反爬虫的一些内容:UA、代理、验证码、动态页面等
HTTP协议
-
什么是协议?
双方规定的传输形式
-
端口(常见端口)
http(80)、https(443)、ssh(22)、mysql(3306)、redis(6379)、mongo(27017)、ftp(21)
-
HTTP协议:应用层的协议
-
什么是HTTP协议?
- HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写。它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定义了今天普遍使用的一个版本——HTTP 1.1。
- HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
-
HTTP响应模型
HTTP协议永远都是客户端发起请求,服务器回送响应。见下图所示:
这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。
-
工作流程
一次HTTP操作称为一个事务,其工作过程可分为四步:
- 首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作开始。
- 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源定位符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
- 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
- 客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。
如果在以上过程中的某一步出现错误,那么产生错误的信息将返回到客户端,有显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,用户只要用鼠标点击,等待信息显示就可以了。
-
参考链接;参考书籍:《图解HTTP协议》
-
网站原理
-
-
HTTP请求
-
HTTP请求组成
一个HTTP请求报文由请求行(request line)、请求头部(headers)、空行(blank line)和请求数据(request body)4个部分组成。
-
请求行
请求行分为三个部分:请求方法、请求地址URL和HTTP协议版本,它们之间用空格分割。例如,
GET /index.html HTTP/1.1
。-
HTTP 请求方法
序号 方法 描述 1 GET 请求指定的页面信息,并返回实体主体。 2 HEAD 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头 3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。 4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。 5 DELETE 请求服务器删除指定的页面。 6 CONNECT HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。 7 OPTIONS 允许客户端查看服务器的性能。 8 TRACE 回显服务器收到的请求,主要用于测试或诊断。 9 PATCH 是对 PUT 方法的补充,用来对已知资源进行局部更新 。 HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。 -
请求地址URL
- URL(uniform resource locator):统一资源定位符,是一种资源位置的抽象唯一识别方法。
- 组成:<协议>://<主机>:<端口>/<路径>
端口和路径有时可以省略(HTTP默认端口号是80)
- 图示
-
-
协议
协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1
-
常见请求头
- accept:浏览器通过这个头告诉服务器,它所支持的数据类型
- Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集
- Accept-Encoding:浏览器通过这个头告诉服务器,支持的压缩格式
- Accept-Language:浏览器通过这个头告诉服务器,它的语言环境
- Host:浏览器通过这个头告诉服务器,想访问哪台主机
- If-Modified-Since: 浏览器通过这个头告诉服务器,缓存数据的时间
- Referer:浏览器通过这个头告诉服务器,客户机是哪个页面来的 防盗链
- Connection:浏览器通过这个头告诉服务器,请求完后是断开链接还是何持链接
- X-Requested-With: XMLHttpRequest 代表通过ajax方式进行访问
-
-
HTTP响应
HTTP响应报文由状态行(status line)、相应头部(headers)、空行(blank line)和响应数据(response body)4个部分组成。
-
状态行
状态行由3部分组成,分别为:协议版本、状态码、状态码扫描。其中协议版本与请求报文一致,状态码描述是对状态码的简单描述。
-
HTTP状态码分类
分类 分类描述 1** 信息,服务器收到请求,需要请求者继续执行操作 2** 成功,操作被成功接收并处理 3** 重定向,需要进一步的操作以完成请求 4** 客户端错误,请求包含语法错误或无法完成请求 5** 服务器错误,服务器在处理请求的过程中发生了错误 -
HTTP状态码列表
状态码 状态码英文名称 中文描述 100 Continue 继续。客户端应继续其请求 101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 200 OK 请求成功。一般用于GET与POST请求 201 Created 已创建。成功请求并创建了新的资源 202 Accepted 已接受。已经接受请求,但未处理完成 203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 206 Partial Content 部分内容。服务器成功处理了部分GET请求 300 Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI 303 See Other 查看其它地址。与301类似。使用GET和POST请求查看 304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 305 Use Proxy 使用代理。所请求的资源必须通过代理访问 306 Unused 已经被废弃的HTTP状态码 307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向 400 Bad Request 客户端请求的语法错误,服务器无法理解 401 Unauthorized 请求要求用户的身份认证 402 Payment Required 保留,将来使用 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求 404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 405 Method Not Allowed 客户端请求中的方法被禁止 406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求 407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 408 Request Time-out 服务器等待客户端发送的请求时间过长,超时 409 Conflict 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突 410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息 412 Precondition Failed 客户端请求信息的先决条件错误 413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理 415 Unsupported Media Type 服务器无法处理请求附带的媒体格式 416 Requested range not satisfiable 客户端请求的范围无效 417 Expectation Failed 服务器无法满足Expect的请求头信息 500 Internal Server Error 服务器内部错误,无法完成请求 501 Not Implemented 服务器不支持请求的功能,无法完成请求 502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求 505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理
-
-
响应头
- Location: 服务器通过这个头,来告诉浏览器跳到哪里
- Server:服务器通过这个头,告诉浏览器服务器的型号
- Content-Encoding:服务器通过这个头,告诉浏览器,数据的压缩格式
- Content-Length: 服务器通过这个头,告诉浏览器回送数据的长度
- Content-Language: 服务器通过这个头,告诉浏览器语言环境
- Content-Type:服务器通过这个头,告诉浏览器回送数据的类型
- Refresh:服务器通过这个头,告诉浏览器定时刷新
- Content-Disposition: 服务器通过这个头,告诉浏览器以下载方式打数据
- Transfer-Encoding:服务器通过这个头,告诉浏览器数据是以分块方式回送的
- Expires: -1 控制浏览器不要缓存
- Cache-Control: no-cache
- Pragma: no-cache
-
响应数据
用于存放需要返回给客户端的数据信息。
-
-
HTTPS的工作原理
我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。
客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示。- 客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
- Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
- 客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
- 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
- Web服务器利用自己的私钥解密出会话密钥。
- Web服务器利用会话密钥加密与客户端之间的通信。
-
HTTPS和HTTP的区别主要如下:
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
- 参考链接
一个网页的呈现,中间不止一次 http 请求,平均一个网页差不多 10-15 个 http 请求,这是我们可以使用抓包工具进行处理信息。
-
Chrome抓包
- 右键 -> 检查 -> network3
- 点击请求,右边栏请求详细信息
- 右边栏:request headers response
- query string:get 参数
- form data:post 参数
-
Fiddler
-
配置
1
2
3
4
5
6tools==>options==>https
选中:capture https
decrypt https trafic
ignore xxx
点击右边的action,信任根证书
配置完毕,fiddler关闭重启即可 -
抓包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<>: html内容
{json}: json数据,很有可能就是个接口
{css}: css文件
{js}: js文件
停止抓取: file==》capture 点击就会切换
点击请求,右边选中 Inspectors
右上: http请求信息
raw: 请求头部的详细信息
webforms:请求所带参数,query_string formdata
右下: http响应信息
首先点击黄色条进行解码
raw: 响应的所有信息
headers:响应头
json: 接口返回的内容
左下黑色框,输入指令
clear: 清除所有请求
select json: 快速选择所有json请求
select image:图片请求
select html: html请求
?内容: 搜索包含这个内容的所有请求,敲enter执行 -
Fiddler中文版
-
会话图标
-
-
Sublime
-
下载并安装然后使用下边注册码激活软件
1
2
3
4
5
6
7
8
9
10
11
12
13----- BEGIN LICENSE -----
Member J2TeaM
Single User License
EA7E-1011316
D7DA350E 1B8B0760 972F8B60 F3E64036
B9B4E234 F356F38F 0AD1E3B7 0E9C5FAD
FA0A2ABE 25F65BD8 D51458E5 3923CE80
87428428 79079A01 AA69F319 A1AF29A4
A684C2DC 0B1583D4 19CBD290 217618CD
5653E0A0 BACE3948 BB2EE45E 422D2C87
DD9AF44B 99C49590 D2DBDEE1 75860FD2
8C8BB2AD B2ECE5A4 EFC08AF2 25A9B864
------ END LICENSE ------​ ; -
安装插件管理器(2种方式):packagecontrol
- 指令安装:
按view下面的 show console, 输入如下指令敲enter即可1
import urllib.request,os; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); open(os.path.join(ipp, pf), 'wb').write(urllib.request.urlopen( 'http://sublime.wbond.net/' + pf.replace(' ','%20')).read())
- 下载packagecontrol包放到指定位置即可(搜教程)
- 指令安装:
-
安装插件
- 输入快捷键ctrl+shift+p
- 输入pci,选中 install packages
- 进来后输入想要安装的插件名字点击就能安装,如:ChineseLocalizations(汉化插件)
-
解决输入pci,找不到包库的问题
输入如下指令,敲enter
1
import urllib.request,os,hashlib; h = 'eb2297e1a458f27d836c04bb0cbaf282' + 'd0e7a3098092775ccb37ca9d6b2e4b7d'; pf = 'Package Control.sublime-、package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); by = urllib.request.urlopen( 'http://packagecontrol.io/' + pf.replace(' ', '%20')).read(); dh = hashlib.sha256(by).hexdigest(); print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)
-
urllib库
-
简介
- 模拟浏览器发送请求的库,Python自带
- Python2:urllib、urllib2
- Python3: urllib.request 、urllib.parse
- 字符串 ==> 字节类型之间的转化
encode()
:字符串 ==> 字节类型- 如果小括号里面不写参数,默认是utf8
- 如果写,你就写 gbk
decode()
:字节类型 ==> 字符串- 如果不写,默认utf8
- 如果写,写gbk
- 示例
1
2
3
4
5import urllib.request
url = 'http://www.baidu.com/'
response = urllib.request.urlopen(url=url)
print(response.read().decode())
-
urllib.request
urlopen(url)
urlretrieve(url, image_path)
- 示例
1
2
3
4
5
6
7
8
9
10import urllib.request
# 下载图片
image_url = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1597694880959&di=6ab8a1ca4e859d02b8c498d4f29244c8&imgtype=0&src=http%3A%2F%2Fimages.china.cn%2Fattachement%2Fjpg%2Fsite1000%2F20170424%2F7427ea210a2c1a677cda59.jpg'
# response = urllib.request.urlopen(image_url)
# with open('meiNv.jpg', 'wb')as fp:
# fp.write(response.read())
urllib.request.urlretrieve(image_url, 'mei.jpg')
-
urllib.parse
quote
:url编码函数,将中文进行转化为%xxxunquote
:url解码函数,将%xxx转化为指定字符urlencode
:给一个字典,将字典拼接为query_string,并且实现了编码的功能- 示例:
1
2
3
4
5
6
7
8
9
10
11import urllib.parse
# https://www.baidu.com/s?ie=UTF-8&wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
# url只能由特定的字符组成:字母、数字、下划线
# 如果出现其他的,比如:$、空格、中文等,就要对其进行编码
url = 'https://www.baidu.com/s?ie=UTF-8&wd=周杰伦'
ret = urllib.parse.quote(url)
print(ret)
re = urllib.parse.unquote(ret)
print(re)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30import urllib.parse
url = 'http://www.baidu.com/index.html'
# url = http://www.baidu.com/index.html?name=goudan&age=18&sex=nv&height=180'
# 假如参数有 name age sex height
name = '狗蛋'
age = 18
sex = '女'
height = '180'
data = {
'name': name,
'age': age,
'sex': sex,
'height': height,
'weight': 180,
}
query_string = urllib.parse.urlencode(data)
url = url + query_string
# 遍历字典
# lt = []
# for k, v in data.items():
# lt.append(k + '=' + str(v))
# query_string = '&'.join(lt)
# url = url + '?' + query_string
print(url)
-
response
read()
:读取响应内容,内容是字节类型geturl()
:获取请求的urlgetheaders()
:获取头部信息,列表里面有元组getcode()
:获取状态码readlines()
:按行读取,返回列表,都是字节类型- 示例
1
2
3
4
5
6
7
8
9
10
11
12
13import urllib.request
url = 'http://www.baidu.com/'
response = urllib.request.urlopen(url=url)
print(response.read())
print(response.geturl())
print(response.url)
print(dict(response.getheaders()))
print(dict(response.headers))
print(response.getcode())
print(response.code)
print(response.readlines())
get方式
1 | import urllib.request |
构建请求头部信息
- 这是反爬第一步
- 伪装自己的UA,让服务端认为你是浏览器在上网
- 构建请求对象:
urllib.request.Request()
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import urllib.request
import urllib.parse
url = 'http://www.baidu.com/'
# response = urllib.request.urlopen(url)
# print(response.read().decode())
# Python默认User-Agent: Python-urllib/3.6
# 自己要伪装的头部
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'
}
# 构建请求对象
request = urllib.request.Request(url=url, headers=headers)
# 发送请求
response = urllib.request.urlopen(request)
print(response.read().decode())