python爬虫基础Ⅰ——requests、BeautifulSoup:书本信息



# 基础爬虫部分Ⅰ ## 什么是爬虫呀?

爬虫,从本质上来说,就是利用程序在网上拿到对我们有价值的数据。

爬虫能做很多事,能做商业分析,也能做生活助手,比如……详细还是看这里吧555→网络爬虫 (-v-)

通俗来说呢,我们平时使用浏览器搜索,浏览器就会向服务器发起请求(request),服务器再回个响应(response)给浏览器。爬虫也就是模仿人操作的这一个过程,去向服务器发起请求……话不多说。咱们接下来的每一个爬虫作业主要分为步骤:获取数据 -> 解析数据 -> 提取数据 -> 储存数据

第0步:获取数据。爬虫程序会根据我们提供的网址,向服务器发起请求,然后返回数据。

第1步:解析数据。爬虫程序会把服务器返回的数据解析成我们能读懂的格式。

第2步:提取数据。爬虫程序再从中提取出我们需要的数据。

第3步:储存数据。爬虫程序把这些有用的数据保存起来,便于你日后的使用和分析。

真的话不多说了,我们开始吧~!


requests


1. 安装

在Mac电脑里打开终端软件(terminal),输入pip3 install requests;Windows电脑打开命令提示符(cmd),输入pip install requests


2. requests.get()

import requests
#引入requests库
res = requests.get('URL')
#requests.get是在调用requests库中的get()方法,它向服务器发送了一个请求,括号里的参数'URL'是你需要的数据所在的网址,然后服务器对请求作出了响应。
#把这个响应返回的结果赋值在变量res上。

打印一下type(res),发现它是一个对象,属于requests.models.Response类。那既然是对象,就看看这个对象有什么属性和方法可供我们操作。


3. Response对象的常用属性

属性 作用
response.status_code 请求HTTP回应的各种相应的状态码
response.content 把response对象转换为二进制数据
response.text 把response对象转换为字符串数据
response.encoding 定义response对象的编码

这里还是解释一下吧~~!

觉得简单的可以直接跳过嗷

(1 )response.status_code

>>> import requests
>>> res = requests.get('https://www.baidu.com/')
>>> print(res.status_code)
200 #200表明请求已成功
>>> print(res.text)
#篇幅太长
常见相应状态码解释
响应状态吗 说明 举例 说明
1xx 请求收到 100 继续提出请求
2xx 请求成功 200 成功
3xx 重定向 305 应使用代理访问
4xx 客户端错误 403 禁止访问
5xx 服务器端错误 503 服务不可用

具体的借鉴一下其他人整理的关于请求HTTP回应的各种状态码:HTTP各种相应的状态码


(2) response.content

接着的属性是response.content,它能把Response对象的内容以二进制数据的形式返回,适用于图片、音频、视频的下载,看个例子你就懂了。

假如我们想下载这张图片,它的URL是:https://res.pandateacher.com/2018-12-18-10-43-07.png

那么代码可以这样写:

import requests
res = requests.get('https://res.pandateacher.com/2018-12-18-10-43-07.png')
#发出请求,并把返回的结果放在变量res中
pic = res.content
#把Reponse对象的内容以二进制数据的形式返回
photo = open('ppt.jpg','wb')
#新建了一个文件ppt.jpg,这里的文件没加路径,它会被保存在程序运行的当前目录下。
#图片内容需要以二进制wb读写。(open函数是文件处理里边的,简单简单哦)
photo.write(pic) 
#获取pic的二进制内容
photo.close()
#关闭文件

这样,我们的图片就下载成功啦~


(3) response.text

继续看response.text,这个属性可以把Response对象的内容以字符串的形式返回,适用于文字、网页源代码的下载。

举个例子,下载小说《三国演义》的第一章:

import requests
#引用requests库
res = requests.get('https://localprod.pandateacher.com/python-manuscript/crawler-html/sanguo.md')
#下载《三国演义》第一回,我们得到一个对象,它被命名为res
novel = res.text
#把Response对象的内容以字符串的形式返回
print(novel[:800])
#现在,可以打印小说了,但考虑到整章太长,只输出800字看看就好。在关于列表的知识那里,前面说过[:800]的意思了~!

诶,为什么会出现一段乱码呢?

这是因为这个超级简单的网页数据的编码类型是'utf-8'(是设计这个网页的人告诉我的!)。用requests.get()发送请求后,我们得到一个Response对象,其中,requests模块会对数据的编码类型做出自己的判断。但是,这个Response对象判断编码类型是'gbk'。这样一来,跟数据本身的编码'utf-8'就不一致了,所以打印出来,就是一堆乱码。(这里后边也会再提到的,关于编码类型主要有utf-8、gbk、gbk2312等,想了解的找度娘嗷~~python也有相应的编码和解码的方法~)


(4) response.encoding

这时我们就要用encoding来编码为utf-8,然后就不会有乱码啦:

import requests
res = requests.get('https://localprod.pandateacher.com/python-manuscript/crawler-html/sanguo.md')
res.encoding = 'utf-8'
#定义Reponse对象的编码为utf-8。
novel = res.text
print(novel[:800])

首先,目标数据本身是什么编码是未知的。用requests.get()发送请求后,我们会取得一个Response对象,其中,requests库会对数据的编码类型做出自己的判断。但是!这个判断有可能准确,也可能不准确。

如果它判断准确的话,我们打印出来的response.text的内容就是正常的、没有乱码的,那就用不到res.encoding

如果判断不准确,就会出现一堆乱码,那我们就可以去查看目标数据的编码(一般是网页源码的charset属性值),然后再用res.encoding把编码定义成和目标数据一致的类型即可。

在实际应用上,遇上文本的乱码问题,才考虑用res.encoding


robot协议

通常情况下,服务器不太会在意小爬虫,但是,服务器会拒绝频率很高的大型爬虫和恶意爬虫,因为这会给服务器带来极大的压力或伤害。

不过,服务器在通常情况下,对搜索引擎是欢迎的态度(刚刚讲过,谷歌和百度的核心技术之一就是爬虫)。当然,这是有条件的,而这些条件会写在Robots协议。

Robots协议是互联网爬虫的一项公认的道德规范,它的全称是“网络爬虫排除标准”(Robots exclusion protocol),这个协议用来告诉爬虫,哪些页面是可以抓取的,哪些不可以。

查看网站的robots协议,只需要在网站的域名后加上/robots.txt就可以了

比如淘宝的: http://www.taobao.com/robots.txt

协议里最常出现的英文是AllowDisallowAllow代表可以被访问,Disallow代表禁止被访问。而且有趣的是,淘宝限制了百度对产品页面的爬虫,却允许谷歌访问。

当你在爬取网站数据的时候,别忘了先看看网站的Robots协议是否允许你去爬取。

同时,限制好爬虫的速度,对提供数据的服务器心存感谢,避免给它造成太大压力,维持良好的互联网秩序,也是我们该做的事。


需要了解一下HTML

1. 查看网页的HTML代码

打开网页(随便找个网页打开就ok)后,按F12Fn+F12),浏览器弹出了一个标签页,就是HTML源代码了。(下边这个红框框没啥用的,我懒得换图)
在这里插入图片描述
夹在尖括号<>中间的字母,它们叫做【标签】。标签通常是成对出现的,一个是开始标签,后边一个是结束标签。不过,也有标签是形单影只地出现,比如HTML代码的第四行<meta charset="utf-8">(定义网页编码格式为 utf-8)。开始标签+结束标签+中间的所有内容,它们在一起就组成了【元素】(element)。

2. 最简单的HTML文档

打开记事本,保存下面的代码,保存格式.html,就是一个最简单的HTML了。

<html>
	<head>
		<meta charset="utf-8"> 
	</head>
    <body>
        <h1>我是一级标题</h1>
        <h2>我是二级标题</h2>
        <h3>我是三级标题</h3>
        <p>我是一个段落啦。一级标题、二级标题和我,我们三个一起组成了body。
         </p>
    </body>
</html>

3. HTML属性

在标签里面,属性名="属性值",如 name="value"。再举例几个常用的属性:

链接一般都由<a>标签定义,href属性用于规定指向页面的URL

还有class用于标识一系列的元素,id属性用于标识唯一的元素。

emm,好像这些够用了吧,就不在此赘述辽。


BeautifulSoup

1. 获取与解析数据

由于BeautifulSoup不是Python标准库,需要单独安装它,在终端输入一行代码运行:pip install BeautifulSoup4。(Mac电脑需要输入pip3 install BeautifulSoup4)后边不再说这个安装问题了,都是一样的操作!!

显然,我们可以使用BeautifulSoup解析和提取网页中的数据。

我认为讲这些不如直接上代码来得强,来吧,聪明的你看注释就能懂的啦~

之后先以http://books.toscrape.com/这个网站为例,先来爬下书的目录

import requests
from bs4 import BeautifulSoup #导入模块

res = requests.get('http://books.toscrape.com/') #发起请求

print(res.status_code) #检查请求是否正确响应

html = res.text #把Response对象的内容以字符串的形式返回

soup = BeautifulSoup(html,'html.parser') #把网页解析为BeautifulSoup对象(简称BS对象)
#在括号中,要输入两个参数,第0个参数是要被解析的文本,注意了,它必须必须必须是字符串。
#括号中的第1个参数用来标识解析器,我们要用的是一个Python内置库:html.parser。(它不是唯一的解析器,但是比较简单的)

#到这里先去看下边的第2点
items = soup.find('ul',class_='nav nav-list')
cate = items.find('ul')
cates = cate.find_all('li')
for i in cates:
    print(i.text.strip())

2. find() 和 find_all() 方法

打开那个网页后,右键 - 检查 或者 按F12,再按下图操作:
在这里插入图片描述
这时候右边的开发者工具栏就会在html源代码里定位到对应的位置,可以看到是右边的<div class="side_categories">。接着打开下边的<ul>标签,可以看到很多<li>标签,再打开那里<li>标签看,发现里面的文本就是这个书目的每一个书名:
在这里插入图片描述
而BeautifulSoup对象的两个方法,它们可以匹配html的标签和属性,把BeautifulSoup对象里符合要求的数据都提取出来。它俩的用法基本是一样的,区别在于,find()只提取首个满足要求的数据,而find_all()提取出的是所有满足要求的数据,以列表的形式返回,用法示例:

find(‘标签名’,class_=‘属性名’,id=‘属性名’,=,【还可以使用其它属性,比如style属性等】),find_all也如此。注意:可以只用标签定位,也可以只用属性定位,一个or多个都ok。还有class属性后边要加个"_"

然后我们就可以开始用它们定位啦!我先草草的说一下定位规则:定位了外层标签后可以继续往其内层的标签定位,但是匹配属性呢,只能匹配当前标签里的属性,还是拿个图来说吧!
在这里插入图片描述
但是要注意,你想定位哪个标签,就用哪个标签的属性来匹配
(不懂的话,自己多试试就知道辽 加油ヾ(◍°∇°◍)ノ゙)

items = soup.find('ul',class_='nav nav-list')
#因为我们要获取所有书的目录,可以选择先定位到所有书目标签'li'的外层标签'ul',通过定位'ul'标签和属性提取我们想要的数据。
#(这里还选用了class_属性定位,是因为前面还有其他的'ul'标签。
#而且我这里选用find定位,只会定位到第一个匹配到的。
#为了避免匹配到前边的'ul'标签位置,再加上属性来定位会更精确。
#那这里那么多标签,总不可能一个个翻吧,这时可以在开发者工具按 Ctrl+F ,搜索你想搜的内容,然后就会高亮显示出来啦,像下边我发的图
#哦对了,可以print一下cate的类型,是一个'Tag'对象

cate = items.find('ul')
#接着我这选择了继续定位内层的'ul'标签。

cates = cate.find_all('li')
#这里用的是find_all,返回所有跟'li'标签匹配的'Tag'对象组成的列表。

#好,到这里又可以看下边第3点了。
for i in cates:
    print(i.text.strip())

在这里插入图片描述

3. Tag对象常用方法

方法 / 属性 作用解释
find() 和 find_all() 与BS对象一样,Tag对象也有此方法,这也是为什么能从BS对象定位到外层标签后(得到的是Tag对象),还能再继续定位内层标签(提取Tag中的Tag,得到的依然是Tag对象)
text 提取Tag中的文字,返回类型是 ‘str’。如,Tag.text。
[‘属性名’] 输入参数:属性名,可以提取Tag中的属性的值,返回类型是 ‘str’。如,Tag[‘属性名’],得到的是属性值。(注意只能提取当前所属标签的属性值)
补充:str.strip()

此方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。

注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。

#遍历这个cates列表(每个元素的Tag对象,也是每个 li 元素)
for i in cates:
    print(i.text.strip())
    #打印li中的文字,因为前后都有很多空格,就用这个strip()方法去除。

部分运行结果:
在这里插入图片描述

简单不简单不(/≧▽≦)/

感觉这里还是说的有点详细又有点不详细,哪儿不清楚的可以现在本地编译器多试一试,还不懂呢善用搜索或者问我也尽力解答啦~!也可以来问我拿一个清楚详细流程图,为什么不直接发在这呢,咳咳我不知道0.0

之后这些就不会再那么一步步说了,可能是几句简单的注释,或者没有~!

给个练习吧

要求:爬取网上书店Books to Scrape中的书名+价格+评分,并且打印提取到的信息。
需要注意:如何获取完整的书名,还有评分的获取。
部分运行结果大概这样:
在这里插入图片描述



————————每个人都在抱怨生活不易,可是都在默默为生活打拼————————

发布了16 篇原创文章 · 获赞 113 · 访问量 4895

猜你喜欢

转载自blog.csdn.net/qq_43280818/article/details/96114307