- 本博客是《Python爬虫入门》系列的第一篇博客,主要介绍爬虫涉及到的一些基础知识,如HTTP协议、网页基础知识、Requests库的基本用法等
- 学习交流请联系 obito0401@163.com
文章目录
基本概念
互联网
- 互联网也叫因特网(Internet),是指网络与网络所串联成的庞大网络,这些网络以一组标准的网络协议族相连,连接全世界几十亿个设备,形成逻辑上的单一巨大国际网络。
- 它由从地方到全球范围内几百万个私人的、学术界的、企业的和政府的网络所构成。通过电子、无线和光纤等一系列广泛的技术来实现。
- 这种将计算机网络互相连接在一起的方法可称作“网络互联”,在此基础上发展出来的覆盖全世界的全球性互联网络称为“互联网”,即相互连接在一起的网络。
提示:
互联网并不等于万维网(WWW),万维网只是一个超文本相互链接而成的全球性系统,而且是互联网所能提供的服务之一。互联网包含广泛的信息资源和服务,例如相互关联的超文本文件,还有万维网的应用,支持电子邮件的基础设施、点对点网络、文件共享,以及IP电话服务。
HTTP协议
简介
- HTTP(Hypertext Transfer Protocol)协议,即超文本传输协议,是一个基于“请求与响应”模式的、无状态的应用层协议
- HTTP协议采用URL作为定位网络资源的标识,URL格式为http://host[:port][path]
- host:合法的Internet主机域名或IP地址
- port:端口号,缺省端口为80
- path:请求资源的路径
- URL是通过HTTP协议存取资源的Internet路径,一个URL对应一个数据资源
操作
方法 | 说明 |
---|---|
GET | 请求获取URL位置的资源 |
HEAD | 请求获取URL位置资源的响应消息报告,即获得该资源的头部信息 |
POST | 请求向URL位置的资源后附加新的数据 |
PUT | 请求向URL位置存储一个资源,覆盖原URL位置的资源 |
PATCH | 请求局部更新URL位置的资源,即改变该处资源的部分内容 |
DELETE | 请求删除URL位置存储的资源 |
TRACE | 回显服务器收到的请求,主要用于测试或诊断 |
OPTIONS | 使服务器传回该资源所支持的所有HTTP请求方法 |
网页基础
因为我们抓取的数据常来源于网页,因此有必要了解一下网页的基础知识。
网页组成
网页通常由 HTML 、 CSS 、JavaScript 三部分组成:
- HTML 即超文本标记语言(Hypertext Markup Language),用来创建网页
- CSS 即层叠样式表(Cascading Style Sheets),用于美化网页
- JavaScript 用于用户和网页之间的交互
我们打开 Chrome 浏览器,访问博客站的首页,打开 F12 开发者工具,可以看到:
在选项 Elements 中可以看到网页的源代码,这里展示的就是 HTML 代码
- 不同类型的文字通过不同类型的标签来表示,如图片用
<img>
标签表示,视频用<video>
标签表示,段落用<p>
标签表示,它们之间的布局又常通过布局标签<div>
嵌套组合而成,各种标签通过不同的排列和嵌套才形成了网页的框架 - 在右边 Style 标签页中,显示的就是当前选中的 HTML 代码标签的 CSS 层叠样式。层叠是指当在HTML中引用了数个样式文件,并且样式发生冲突时,浏览器能依据层叠顺序处理。“样式”指网页中文字大小、颜色、元素间距、排列等格式
- JavaScript 在 HTML 代码中常用
<script>
进行包裹,可直接写在 HTML 页面,也可以文件的形式引入
网页结构
我们来手写一个简单 HTML 页面来感受下:
创建一个文本文件,将后缀名改为 .html ,比如demo.html,写入如下内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
</head>
<body>
<div id="container">
<div class="wrapper">
<h1>Hello World</h1>
<div>Hello Python.</div>
</div>
</div>
</body>
</html>
观察代码,我们发现:
- 整个文档是以 DOCTYPE 来开头的,这里定义了文档类型是 html ,整个文档最外层的标签是
<html>
,并且结尾还以</html>
来表示闭和 - 整个 HTML 文档一般分为 head 和 body 两个部分
- 在 head 中,我们一般会指定当前的编码格式为 UTF-8 ,并且使用 title 来定义网页的标题,这个会显示在浏览器的标签上面
- body 中的内容一般为整个 html 文档的正文,html的标签由
<h1>
到<h6>
六个标签构成,字体由大到小递减,换行标签为<br>
,链接使用<a>
来创建,herf属性包含链接的URL地址,比如<a href="http://www.baidu.com" >一个指向百度的链接</a>
HTML DOM
在 HTML 中,所有标签定义的内容都是节点,它们构成了一个 HTML DOM 树
根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点:
- 整个文档是一个文档节点
- 每个 HTML 元素是元素节点
- HTML 元素内的文本是文本节点
- 每个 HTML 属性是属性节点
- 注释是注释节点
HTML DOM 将 HTML 文档视作树结构。这种结构被称为节点树:
节点树中的节点彼此拥有层级关系
父(parent)、子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹):
- 在节点树中,顶端节点被称为根(root)
- 每个节点都有父节点、除了根(它没有父节点)
- 一个节点可拥有任意数量的子
- 同胞是拥有相同父节点的节点
下面的图片展示了节点树的一部分,以及节点之间的关系:
使用开发者工具检查网页
如果想要编写一个爬取网页内容的爬虫程序,在动手编写前,最重要的准备工作可能就是检查目标网页。下面以Chrome为例,看看如何使用开发者工具。
以python官网的“python之禅”为例,首先在Chrome中打开网址 ,可以选择“菜单”中的“更多工具”→“开发者工具”,也可以直接在网页内容中右击并选择“检查”选项,还可以按f12键。效果如下图所示:
Chrome的开发者模式为用户提供了下面几组工具:
- Elements:允许用户从浏览器的角度来观察网页,用户可以借此看到Chrome渲染页面所需要的HTML、CSS和DOM(Document Object Model)对象
- Network:可以看到网页向服务气请求了哪些资源、资源的大小以及加载资源的相关信息。此外,还可以查看HTTP的请求头、返回内容等
- Source:即源代码面板,主要用来调试JavaScript
- Console:即控制台面板,可以显示各种警告与错误信息。在开发期间,可以使用控制台面板记录诊断信息,或者使用它作为shell在页面上与JavaScript交互
- Performance:使用这个模块可以记录和查看网站生命周期内发生的各种事情来提高页面运行时的性能
- Memory:这个面板可以提供比Performance更多的信息,比如跟踪内存泄漏。
- Application:检查加载的所有资源
- Security:即安全面板,可以用来处理证书问题等
Requests库
简介
- Requests库是Python中最为常用的第三方爬虫库,用它可以解决中小规模的爬取需求。简单易用,备受欢迎。
- 详情可见官方网站
方法
Requests库的方法和HTTP协议的操作大多数都是对应的,因此十分易于理解
方法 | 说明 |
---|---|
requests.request() | 构造一个请求,支撑以下各方法的基础方法 |
requests.get() | 获取HTML网页的主要方法,对应于HTTP的GET |
requests.head() | 获取HTML网页头信息的主要方法,对应于HTTP的HEAD |
requests.post() | 向HTML网页提交POST请求的方法,对应于HTTP的POST |
requests.put() | 向HTML网页提交PUT请求的方法,对应于HTTP的PUT |
requests.patch() | 向HTML网页提交局部修改请求的方法,对应于HTTP的PATCH |
requests.delete() | 向HTML网页提交删除请求的方法,对应于HTTP的DELETE |
解析
requests.request()
r = requests.request(method,url,**kwargs)
- method:请求方式,对应get/head/post/put/patch/delete/options七种方法
- url:拟爬取页面的链接
- **kwargs:13个控制访问的参数
- params:字典或字节流,作为参数增加到url中
kv = {“key1”:“value1”,“key2”:“value2”}
r = requests.request(“GET”,‘http://python123.io/ws’,params=kv)
print(r.url)
- data:字典、字节序列或文件对象,作为Request的内容
kv = {“key1”:“value1”,“key2”:“value2”}
r = requests.request(‘POST’,‘http://python123.io/ws’,data=kv)
- json:JSON格式的数据,作为Request的内容
kv = {“key1”:“value1”,“key2”:“value2”}
r = requests.request(‘POST’,“http://python123.io/ws”,json=kv)
- headers:字典,HTTP定制头
hd = {‘user-agent’:‘Chrome/10’}
r = requests.request(‘POST’,‘http://python123.io/ws’,headers=hd)
-
cookies:字典或CookieJar,Request中的cookie
-
auth:元组,支持HTTP认证功能
-
files:字典类型,传输文件
-
timeout:设定超时时间,秒为单位
-
proxies:字典类型,设定访问代理服务器,可以增加登录认证
-
allow_redirects:True/False,默认为True,重定向开关
-
stream:True/False,默认为True,获取内容立即下载开关
-
verify:True/False,默认为True,认证SSL证书开关
-
cert:本地SSL证书路径
requests.get()
r = requests.get(url,params=None,**kwargs)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYXS5crO-1587469611585)(…/images/response.jpg)]
- r:返回一个包含服务器资源的Response对象
- requests.get():构造一个向服务器请求资源的Request对象
- url:拟爬取页面的url连接
- params:url的额外参数,字典或字节流格式,可选
- **kwargs:12个控制访问的参数
Response对象的属性
属性 | 说明 |
---|---|
r.status_code | HTTP请求的返回状态,200表示连接成功,404表示失败 |
r.text | HTTP响应内容的字符串形式,即url对应的页面内容 |
r.encoding | 从HTTP header中猜测的响应内容编码方式 |
r.apparent_encoding | 从内容中分析出的响应内容编码方式(备选) |
r.content | HTTP响应内容的二进制形式 |
Response库的异常
异常 | 说明 |
---|---|
requests.ConnectionError | 网络连接错误异常,如DNS查询失败,拒绝连接等 |
requests.HTTPError | HTTP错误异常 |
requests.URLRequired | URL缺失异常 |
requests.TooManyRedirects | 超过最大重定向次数,产生重定向异常 |
requests.ConnectTimeout | 连接远程服务器超时异常 |
requests.Timeout | 请求URL超时异常 |
r.raise_for_status() | 如果不是200,产生HTTP错误异常 |
requests.head()
requests.head(url,**kwargs)
- url:拟爬取页面的url链接
- **kwargs:12个控制访问的参数
requests.post()
requests.post(url,data=None,json=None,**kwargs)
- url:拟更新页面的url链接
- data:字典、字节序列或文件,Request的内容
- json:JSON格式的数据,Request的内容
- **kwargs:12个控制访问的参数
requests.put()
requests.put(url,data=None,**kwargs)
- url:拟更新页面的url链接
- data:字典、字节序列或文件,Request的内容
- **kwargs:12个控制访问的参数
requests.patch()
requests.patch(url,data=None,**kwargs)
- url:拟更新页面的url链接
- data:字典、字节序列或文件,Request的内容
- **kwargs:12个控制访问的参数
requests.delete()
requests.delete(url,**kwargs)
- url:拟删除页面的url链接
- **kwargs:12个控制访问的参数
框架
import requests
def getHTMLText(url):
try:
r = requests.get(url,timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return "产生异常"
if __name__ == "__main__":
url = "<网址>"
print(getHTMLText(url))
示例
京东商品页面爬取
import requests
url = "https://item.jd.com/100003434260.html" # 爬取网址
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000]) # 输出字符串的前1000项
except:
print("爬取失败")
网络图片爬取
- 网络图片的链接格式为http://www.example.com/picture.jpg
- 由于每个网站对链接的格式设定不同,因此图片链接格式往往显得甚是复杂,但是许多参数都可以简化省略
- 最简单暴力的方法是鼠标右键复制图片地址,然后get即可
# 针对规范路径存储的图片
import requests
import os
url = "http://b-ssl.duitang.com/uploads/item/201512/15/20151215215946_dEQ5F.jpeg"
root = "C:/Users/SHOHOKU/Desktop/Python/Codes/images/" #定义系统存储路径
path = root + url.split('/')[-1] # url链接以/划分的最后一位,即图片的名称
try:
if not os.path.exists(root): #判断根目录是否存在
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url)
with open(path,"wb") as f:
f.write(r.content)
f.close()
print("文件保存成功")
else:
print("文件已存在")
except:
print("爬取失败")
豆瓣TOP250榜单爬取
import requests
import os
if not os.path.exists('image'):
os.mkdir('image')
def parse_html(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"} # 伪装头部信息
res = requests.get(url, headers=headers)
text = res.text
item = []
for i in range(25):
text = text[text.find('alt')+3:]
item.append(extract(text))
return item
def extract(text):
text = text.split('"')
name = text[1]
image = text[3]
return name, image
def write_movies_file(item, stars):
print(item)
with open('C:/userdouban_film.txt','a',encoding='utf-8') as f:
f.write('排名:%d\t电影名:%s\n' % (stars, item[0]))
r = requests.get(item[1])
with open('image/' + str(item[0]) + '.jpg', 'wb') as f:
f.write(r.content)
def main():
stars = 1
for offset in range(0, 250, 25):
url = 'https://movie.douban.com/top250?start=' + str(offset) +'&filter='
for item in parse_html(url):
write_movies_file(item, stars)
stars += 1
if __name__ == '__main__':
main()