快速入门爬虫

前言

本人正在学习人工智能,当然,除了为做ctf比赛ai部分的题意外,也是想自己搞点小玩意玩玩,而学习爬虫又是训练模型时获取数据的不二手段,那么以下开启作者的学习部分

爬虫第一步——获取网站内容

通过python的requests库,用代码实现获取网页内容,也就是发送http请求

1
pip install requests

首先通过以上命令来拉取requests库,然后我们来学习http常见的请求方法

  • GET
    • 作用于获得数据,比如我们浏览某个网页,浏览器就会向服务器发送GET请求得到网页内容
  • POST
    • 作用于创建数据,比如我们注册账号,浏览器就会向服务器发送POST请求来存储我们的注册信息
      以下列举一个完整的http请求例子
1
2
3
4
5
6
7
POST/user/info?new_user=true HTTP/1.1
Host: www.example.com
User-Agent:curl/7.77.0
Accept:*/*

{"username":"LNexaminee",
"blog":"bmx6132.github.io"}

而以上请求分为三部分

  • 请求行
    • POST/user/info?new_user=true HTTP/1.1
      
      1
      2
      3
      4
      5
      * post为方法类型
      * /user/info是资源路径
      * 资源路径表示你要访问服务器的哪个资源,就比如以下网址:
      ~~~http
      news.4399.com/zmxy6/search.php?q=%B7%E2&start=3
      > 第一个/之前的news.4399.com就是资源路径的根,之后的/zmxy6/search就是要访问的资源的路径,而?后面的q=%B7%E2&start=3就是查询参数,可以传递个服务器额外的信息,不同的信息之间用&来链接,就比如q=%B7%E2,q是query的缩写,%B7%E2是url编码之后的产物,也就是说用户要查询 **%B7%E2** 这个东西解码之后的内容,start=3说明从第3条搜索结果开始显示
    • HTTP/1.1是协议版本,也就是http协议的版本,如HTTP/1.0 HTTP/2.0 HTTP/0.9

  • 请求头
    • Host: www.example.com
      User-Agent:curl/7.77.0
      Accept:*/*
      
      1
      2
      3
      4
      5
      6
      7
        * host指的是主机域名,他与请求行中的资源路径在一起可以组成完成的网址,如上述的news.4399.com
      * user—agent用来告诉服务器客户端的相关信息,比如请求是浏览器发出来的还是其他东西发出来的,类型是什么,版本是什么(请求如果是curl命令行发出的就是curl/7.77.0,Requests就是python_Requests/2.25.1啥的)
      * Accept是在告诉服务器客户端想接收的响应数据是什么类型的*/*就是啥类型都可以,来者不拒
      * 请求体
      * ~~~http
      {"username":"LNexaminee",
      "blog":"bmx6132.github.io"}
    • 请求体中是客服端传输给服务器的任意数据,当然get方法的请求体一般是空的,原因请见上述get和post之间的关系

而在服务器接收到请求之后,也会进行响应,也就是http响应下面同样举一个例子

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Date: Mon, 25 Feb 2025 14:15:06 GMT
Content-Type: text/html; charset=utf-8

<!DOCTYPE html>
<head><title>首页</title></head>
<body><h1>BMX</h1><p>hello</p></body>
</html>
  • 响应行
    • HTTP/1.1 200 OK
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
        * 响应行包括协议版本(HTTP/1.1),状态码(200),状态信息(OK)以下列举一些常见的状态信息

      |状态码&状态信息|意义
      |:---:|:---:
      |200 OK|客户端请求成功
      |301 Moved Permanently|资源被永久移动到新地址
      |400 Bad Request|客户端不能被服务器所理解
      |401 Unauthorized|请求未经授权
      |403 Forbidden|服务器拒绝提供服务
      |404 Not Found|请求资源不存在
      |418 I'm a teatop|反爬虫
      |429|请求次数过多
      |500 Internal Server Error|服务器发生不可预期的错误
      |503 Server Unavailable|服务器当前不能处理客户端的请求
      * 响应头
      * ~~~http
      Date: Mon, 25 Feb 2025 14:15:06 GMT
      Content-Type: text/html; charset=utf-8
    • 响应头包含一些告诉客户端的信息,如date日期,content-type告诉用户返回的内容格式以及编码形式
  • 响应体
    • <!DOCTYPE html>
      <head><title>首页</title></head>
      <body><h1>BMX</h1><p>hello</p></body>
      </html>
      
      1
      2
      3
      4
      5
      6
      7
      8
        * 整体来看,响应体其实就是服务器想给客户端显示的数据内容,以上就是一个html格式的回显

      那么了解了以上信息之后,我们开始正式使用python来进行http请求
      ~~~python
      import requests
      response=requests.get("https://www.4399.com/")#库函数get完成http请求
      print(response)#注意类
      print(response.status_code)#查询状态信息
      获得以下输出
1
2
<Response [200]>
200

可以看到状态码为200,说明请求成功,而在写代码的过程中,为了更好的纠错,提高代码的可维护性和鲁棒性,可以加上以上字段

1
2
3
4
5
6
if response.status_code>=400 and response.status_code<500:
print("客户端错误")
exit()
elif response.status_code>=500:
print("服务器错误")
exit()

亦或者

1
2
3
4
5
if response.ok:
print(response.text)#获取响应体内容
else:
print("请求错误")
exit()

但是实操的同学又发现了问题就是有的时候,你的终端会显示如下内容

1
2
3
print(response.text)
~~~~~^^^^^^^^^^^^^^^
UnicodeEncodeError: 'gbk' codec can't encode character '\xd0' in position 313: illegal multibyte sequence

以上内容是因为在windows环境下,你的编码形式并非utf-8而是gbk,所以推荐加上以上内容

1
2
3
import sys
import io
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')#改变标准输出的默认编码

这里是一个专门练习爬虫的网站,可以把作者恶趣味的4399改成这个
but,话又说回来,如果我们单纯爬取信息然后留下python的痕迹太高调了,所以我们可以用以下方式来伪装我们的请求头

1
2
headers={"User-Agent": "Mozilla/5.0(Windows NT 10.0: Win64; x64)"}
#注意,这是一个字典类型的变量

那么下面实战一下——用python来获取豆瓣评分top250的电影(相当于F12)

1
2
3
4
5
6
import requests
import sys
import io
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')
douban=requests.get("http://movie.douban.com/top250")
print(douban)

但很不幸,我们发现他的返回值是418,也就是他不吃我们Mozilla/5.0(Windows NT 10.0: Win64; x64)这套,那我们应该把头改成什么才能绕过呢
答案是去网站里抄答案
方法
点击结束之后在右侧找到user-agent,之后把后面的东西全部复制下来填在head后面如下

1
2
3
4
5
6
7
import requests
import sys
import io
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')
head={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0"}
douban=requests.get("http://movie.douban.com/top250",headers=head)
print(douban.text)

就可以美美爬取网站啦

爬虫第二步——解析网页内容

用python的Beautiful soup库来进行html网页解析

1
pip install bs4

但在用工具之前,我们还是要学习一下html文本,至少要基本懂得他的结构原理

首先我们要了解到,一个网站有三大要素:

  • HTML
    • 定义网页的结构和信息
  • CSS
    • 定义网页的样式
  • JavaScript
    • 定义网页和用户的交互逻辑
      而爬虫是在跟网页的数据信息打交道,所以我们着眼于HTML

以下是一个最简单的HTML语句

1
2
3
<!DOCTYPE HTML>
<html>
</html>

每个被<>包括的内容都是一个标签

1
<!DOCTYPE HTML>

用于告知浏览器这个文件类型是一个HTML文件

1
2
<html>
</html>

没有斜杠开头的是起始标签,有斜杠开头的是终止标签

而html文件也可以被看作是一个文件夹,其实标签可以被认为是这个文件夹的根目录,其他的所有元素都要被放置于这个目录之下,也就是在起始标签和终止标签之内

1
2
3
4
5
6
<html>
<body>
<h1>title</h1>
<p>text</p>
</body>
</html>

以上是一个实例,body是一个文件的主体部分,h1是一级标题,p是文本段落用于换行,有点md的感觉,这么看其实他也挺工整的对吧。。。

以上就先展示他的基本原理,更多内容读者可以自行去寻找学习资料,因为毕竟我们的侧重点是爬虫而不是web开发,嘿嘿。

那么下面我们就讲解如何用Beautiful soup来解析HTML的内容

首先引入库函数然后将爬取到的html格式信息发入bs的架构中

1
2
from bs4 import BeautifulSoup
soup=BeautifulSoup(douban.text,"html.parser")#将上一步我们爬到的东西传入beautifulsoup这个架构中,并且指定编译器

而beautifulsoup会把我们的HTML构建成一个像树一样的数据结构如下图
htmltosoup
所以你可以理解为目前soup这个对象就好像你的文件夹一样,下面我们来看看他的特性和方式

1
print(soup.p,soup.img)

比如上述代码,我就查看了soup中的第一个文本段和img元素

但因为我们可能更需要的是网页中的每一个元素的价格或者书名啥的,所以我们呢可以f12打开看源代码,看看你想要的数据具体存在哪个元素中,是img,还是p或者是h123456。。。

但是这也伴随着第二个难点的出现就是网站里肯定有很多其他的p类型,img类型或者h123456等等,如何过滤到其他你不想要的同类型元素只留下你需要的元素呢

这就要利用他的其他的一些特点了,比如我们来看这个这个豆瓣电影top250的源代码
douban
我们往下翻找就能看到,我想要的电影名之一:肖申克的救赎

而我们发现了一个规律就是我们可以从每一个width为100的img类中找寻其中的alt元素来查找电影名

1
2
3
all_movie=soup.findAll("img",attrs={"width":"100"})
for movie in all_movie:
print(movie.get("alt"))

如果不想要显示一些奇奇怪怪的符号或者想要纯净的数据,可以试一下

1
douban.string#伪代码,仅仅注释可以用.string的方法来访问纯净的数据

如果还有更多的操作要求,可以使用切片之类的方式来进行操作,或者现用现查一些函数,都是非常方便的

以上基本的爬虫功能已经介绍结束,后面数据分析会在之后可能更新的爬虫进阶中介绍,作者要去准备这个杯那个杯了,再见我的朋友