爬虫初体验


一、什么是爬虫

1、 网络爬虫,简称爬虫,是一种按照一定的规则,自动地抓取互联网信息的程序或者脚本。

2、爬虫做的事情其实和蜘蛛是类似的,所以网络爬虫也被称为网络蜘蛛(spider)。蜘蛛在蜘蛛网上爬来爬去,把触手伸到蜘蛛网获取食物,而网络爬虫则是在互联网上爬来爬去,爬取我们需要的数据。
在这里插入图片描述

二、爬虫初体验

1.requests

接下来,我们来学习爬虫中最常用的发起请求的第三方库——requests。下面是 requests 的中文文档页面(https://requests.kennethreitz.org/zh_CN/latest/)。
在这里插入图片描述

2.requests.get() 方法

我们从爬虫的第一步 获取数据 开始,我们来看个例子:

import requests  # 导入 requests 模块

res = requests.get('https://wpblog.x0y1.com')  # 发起请求
print(res)
# 输出:<Response [200]>

我们使用 requests.get(‘网站地址’) 方法向对应的网站发起了请求,然后我们将返回的结果存到了变量 res 中供后续使用。它的类型是 Response 对象,后面的 200 是状态码,我们后面再细说。

这样我们就发起了一次请求,并将服务器的响应结果存到了变量当中,requests.get() 方法的作用如下图所示:
在这里插入图片描述

该处使用的url网络请求的数据。


三、Response 对象

我们前面通过 requests.get() 方法获取到了网页的数据,作为 Response 对象存到了变量 res,那么我们如何查看它的具体内容呢?

接下来我们来看看 Response 对象的常用属性:

属性含义
res.status_code响应的HTTP状态码
res.text响应内容的字符串形式
res.content响应内容的二进制形式
res.encoding响应内容的编码

1.res.status_code

import requests

res = requests.get('https://wpblog.x0y1.com')
print(res.status_code)
# 输出:200

这里的 200 就是响应的状态码,表示请求成功。当请求失败时会有不同的状态码,不同的状态码有不同的含义,常见的状态码如下:

响应状态码含义例子含义
1xx消息100继续发出请求
2xx请求成功200请求成功
3xx重定向301永久重定向
4xx客户端错误404找不到资源
5xx服务端错误503服务不可用
例:
import requests

res = requests.get('https://wpblog.x0y1.com')

# 补全下行代码
if res.status_code==200:
  print('请求成功')
else:
  print('请求失败')

2.res.text

res.text 返回的是服务器响应内容的字符串形式,也就是文本内容。我们直接看段代码

import requests

res = requests.get('https://wpblog.x0y1.com')
print(res.text)

上面代码的运行结果(结果太长省略了一部分)是:

<!DOCTYPE html>
<html lang="zh-CN" class="no-js no-svg">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>(function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement);</script>
<title>扇贝编程 &#8211; 爬虫示例站点</title>
<link rel="alternate" type="application/rss+xml" title="扇贝编程 &raquo; Feed" href="https://wpblog.x0y1.com/?feed=rss2" />
<link rel="alternate" type="application/rss+xml" title="扇贝编程 &raquo; 评论Feed" href="https://wpblog.x0y1.com/?feed=comments-rss2" />
<script type="text/javascript">
	window._wpemojiSettings = {"baseUrl":"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/72x72\/","ext":".png","svgUrl":"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/","svgExt":".svg","source":{"concatemoji":"https:\/\/wpblog.x0y1.com\/wp-includes\/js\/wp-emoji-release.min.js?ver=5.2.3"}};
	!function(a,b,c){function d(a,b){var c=String.fromCharCode;l.clearRect(0,0,k.width,k.height),l.fillText(c.apply(this,a),0,0);var d=k.toDataURL();l.clearRect(0,0,k.width,k.height),l.fillText(c.apply(this,b),0,0);var e=k.toDataURL();return d===e}function e(a){var b;if(!l||!l.fillText)return!1;switch(l.textBaseline="top",l.font="600 32px Arial",a){case"flag":return!(b=d([55356,56826,55356,56819],[55356,56826,8203,55356,56819]))&&(b=d([55356,57332,56128,56423,56128,56418,56128,56421,56128,56430,56128,56423,56128,56447],[55356,57332,8203,56128,56423,8203,56128,56418,8203,56128,56421,8203,56128,56430,8203,56128,56423,8203,56128,56447]),!b);case"emoji":return b=d([55357,56424,55356,57342,8205,55358,56605,8205,55357,56424,55356,57340],[55357,56424,55356,57342,8203,55358,56605,8203,55357,56424,55356,57340]),!b}return!1}function f(a){var c=b.createElement("script");c.src=a,c.defer=c.type="text/javascript",b.getElementsByTagName("head")[0].appendChild(c)}var g,h,i,j,k=b.createElement("canvas"),l=k.getContext&&k.getContext("2d");for(j=Array("flag","emoji"),c.supports={everything:!0,everythingExceptFlag:!0},i=0;i<j.length;i++)c.supports[j[i]]=e(j[i]),c.supports.everything=c.supports.everything&&c.supports[j[i]],"flag"!==j[i]&&(c.supports.everythingExceptFlag=c.supports.everythingExceptFlag&&c.supports[j[i]]);c.supports.everythingExceptFlag=c.supports.everythingExceptFlag&&!c.supports.flag,c.DOMReady=!1,c.readyCallback=function(){c.DOMReady=!0},c.supports.everything||(h=function(){c.readyCallback()},b.addEventListener?(b.addEventListener("DOMContentLoaded",h,!1),a.addEventListener("load",h,!1)):(a.attachEvent("onload",h),b.attachEvent("onreadystatechange",function(){"complete"===b.readyState&&c.readyCallback()})),g=c.source||{},g.concatemoji?f(g.concatemoji):g.wpemoji&&g.twemoji&&(f(g.twemoji),f(g.wpemoji)))}(window,document,window._wpemojiSettings);
</script>

接下来我们来试试用爬虫下载一个小说——孔乙己,它的网址是 。该网址返回的是小说的纯文本格式,源代码和内容是一样的。

import requests

# 获取孔乙己数据
res = requests.get('https://apiv3.shanbay.com/codetime/articles/mnvdu')
# 以写入的方式打开一个名为孔乙己的 txt 文档
with open('孔乙己.txt', 'w') as file:
  # 将数据的字符串形式写入文件中
  file.write(res.text)

上面代码涉及到了文件操作,这里简单介绍一下。

open() 函数是 Python 中的内置函数,用于打开文件,返回值是一个 file 对象。

open() 函数接收的第一个参数为文件名第二个参数为文件打开模式。打开模式默认为 r,是 read 的缩写,表示只读模式。即只能读取内容,不能修改内容。

常用的打开模式有 w(write,只写模式)、b(binary,二进制模式)和 a(append,追加模式,表示在文件末尾写入内容,不会从头开始覆盖原文件)。

Tips:在 w 和 a 模式下,如果你打开的文件不存在,那么 open() 函数会自动帮你创建一个。

这些打开模式还能两两组合,比如:rb 表示以二进制格式打开文件用于读取,wb 表示以二进制格式打开文件用于写入,ab 表示以二进制格式打开文件用于追加写入。

需要注意的是,使用 open() 函数打开文件,操作完毕后,最后一定要调用 file 对象的 close() 方法关闭该文件。所以一般我们像下面这样读写文件:

# 读取文件
file = open('文本.txt')  # 打开模式默认为 r,可省略
print(file.read())  # 调用 read() 方法读取文件内容
file.close()  # 关闭文件

# 写入文件
file = open('文本.txt', 'w')  # 写入模式
file.write('生如夏花')  # 调用 write() 方法写入内容
file.close()  # 关闭文件

为了避免忘记调用 close() 方法关闭文件,导致资源占用、文件内容丢失等问题,推荐使用 with … as … 语法,它在最后会自动帮你关闭文件。

我们通过下面这个例子来对比一下

# 普通写法
file = open('文本.txt', 'w')  # 写入模式
file.write('生如夏花')  # 调用 write() 方法写入内容
file.close()  # 关闭文件

# 使用 with ... as ... 写法
with open('文本.txt', 'w') as file:
  file.write('生如夏花')

可以看到,使用 with … as … 语法后,关闭文件的操作就可以省略了。不仅代码简洁了,也避免了忘记关闭文件的问题。

了解了文件操作之后,我们重新回到之前爬虫的例子,再看一遍代码

import requests

# 获取孔乙己数据
res = requests.get('https://apiv3.shanbay.com/codetime/articles/mnvdu')
# 以写入的方式打开一个名为孔乙己的 txt 文档
with open('孔乙己.txt', 'w') as file:
  # 将数据的字符串形式写入文件中
  file.write(res.text)

我们获取到网页的响应后,以写入模式打开一个名为 孔乙己.txt 的文件,然后调用 write() 方法将响应内容的字符串形式写入到文件中,实现了小说的下载。同理,所有文本内容都可以通过这种方式进行下载,只需将 res.text 写入到文件当中保存即可。

3.res.content

除了文本内容的下载,爬虫还能下载图片、音频、视频等。我们来看一个下载图片的例子:
在这里插入图片描述

以下载上面的图片为例,图片地址是:http://pp.myapp.com/ma_pic2/0/shot_52575843_1_1618363820/0
下载图片的代码如下:

import requests

# 获取图片数据
res = requests.get('http://pp.myapp.com/ma_pic2/0/shot_52575843_1_1618363820/0')
# 以二进制写入的方式打开一个名为 info.jpg 的文件
with open('info.png', 'wb') as file:
  # 将数据的二进制形式写入文件中
  file.write(res.content)

我们可以看到,和下载小说的步骤几乎一样。区别在于图片是用二进制写入的方式,将数据的二进制形式写入文件当中,而不是字符串形式

所以 res.textres.content 的区别是:res.text 用于文本内容的获取、下载,res.content 用于图片、音频、视频等二进制内容的获取、下载。

4.res.encoding

编码是信息从一种形式或格式转换为另一种形式的过程。

常见的编码方式有 ASCII、GBK、UTF-8 等。如果用和文件编码不同的方式去解码,我们就会得到一些乱码。

编码的发展史

我们都知道,计算机的底层是二进制。也就是说,计算机只认识 0 和 1。既然如此,计算机是如何展示文字、符号等信息的呢?

聪明的计算机科学家们想到了编码,将数字和文字、符号一一对应即可。比如 0000 对应 a,0001 对应 b,0010 对应 c(举个例子,实际上并不是这样对应的)。

因为英文字母比较少,加上常用的符号等,总共也就 100 多个。计算机科学家们用一个字节中的 7 位(总共 8 位)定义了一套编码,总共 128(2 的 7 次方)个字符,这就是 ASCII 编码。

随着科技的发展,计算机进入了欧洲国家。128 个字符对美国来说是够用的,但欧洲一些国家的语言,比如法语中,字母上方有注音符号,128 个字符就不够用了。因此欧洲国家决定将最后一个闲置的位也利用上,这样欧洲的编码就有 256(2 的 8 次方)个字符了。

但是不同的国家有不同的字母,这就导致前 128 个字符是一样的,后 128 个字符在不同的国家是不一样的。

不久后,计算机便来到了中国。中国的汉字可是有 10 万多个,256 个是远远不够的。中国计算机科学家们便重新定义了一套编码,也就是 GB2312,这套编码包含了 6763 个常用汉字和一些常用符号等。之后为了扩展能显示的汉字内容,还推出了 GBK 等编码标准。

你可能也发现问题了,每个国家都有自己的编码,还都不一样。发封电子邮件给外国人,在他们看来就都是乱码,这可怎么行!

于是,Unicode(统一码)便出现了。Unicode 是一个很大的集合,现在的规模可以容纳 100 多万个符号,并且每个符号的编码都不一样。

但是 Unicode 有个缺点,就是占用字节过多。英文字母本来只需要一个字节就够了,现在为了统一得用 3、4 个字节,很是浪费!因此导致 Unicode 在很长一段时间内无法推广,直到互联网的出现。

聪明的计算机科学家又想到了新的方法,推出了 UTF-8 编码,UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用 1~4 个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 即解决了乱码问题,也解决了字节浪费的问题,是现在最常用的编码方式。

在这里插入图片描述
你看,编码的发展过程也是磕磕绊绊,一点一点地改进、发展至今的。

Python、爬虫课的学习也是如此,不必一口吃成胖子。慢慢来,一点一点地将知识点消化、吸收,总会有所收获的。

好了,我们回到爬虫的编码。

res.encoding 就是爬虫获取到数据的编码格式,requests 库会根据内容推测编码格式是什么,然后将 res.encoding 设成推测的格式,在访问 res.text 时使用该格式解码。

当推测的格式错误时,即出现乱码时,就需要我们手动给 res.encoding 赋值成正确的编码。我们来看下面的例子:

import requests

res = requests.get('https://www.baidu.com')
print(res.text)
#结果是<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>ç™¾åº¦ä¸€ä¸‹ï¼Œä½ å°±çŸ¥é“</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>æ–°é—»</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>å
³äºŽç™¾åº¦</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前å¿
读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

我们来看看 requests 库推测的编码格式是什么:

import requests

res = requests.get('https://www.baidu.com')
print(res.encoding)
# 输出:ISO-8859-1

我们可以看到,requests 库将编码错误地推测成了 ISO-8859-1 格式。国内网站的编码格式一般都是 UTF-8、GBK 或 GB2312。

上述代码中网站的正确编码格式其实是 UTF-8,我们需要手动将编码修改成 UTF-8,便能显示正确的内容了。

import requests

res = requests.get('https://www.baidu.com')
res.encoding='utf-8'
print(res.text)
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值