步骤
-
获取网页内容:
-
http请求
-
python的Requests库
-
-
解析网页内容
-
html网页结构
-
python的Beautiful Soup库
-
-
储存或分析数据
-
储存进数据库
-
作为ai分析的数据
-
转化为图表显示出来
-
DDoS攻击
通过给服务器发送海量高频请求,大量消耗网页资源,影响其他用户的请求
遵守规则
可以查看该网站的robots.txt文件,了解可爬取的网页路径范围
HTTP(Hypertext Transfer Protocol 超文本传输协议)
-
用户端与服务端之间的请求-响应协议。
-
请求方法:(常用的)
-
GET:获取数据
-
POST:创建数据
-
-
请求的组成:
POST /user/info HTTP/1.1 #请求行(包含方法类型、资源路径、协议版本) Host:www.example.com #请求头 User-Agent:curl/7.77.0 #请求头 Accept:*/* #请求头{"username":"呦呦呦", #请求体 "email":"3078158560@qq.com"} #请求头
-
请求行:包含方法类型、资源路径、协议版本
-
POST:方法类型
-
/user/info:请求路径,后面可以加上查询参数,用于传给服务器额外的信息,不同信息之间用 & 符号分隔,如
www.bilibili.com/video/BV1d54y1g7db?p=3&vd_source=327f3e87e497fe83b3515199232efd15
-
HTTP/1.1:协议版本
-
-
请求头:包含着给服务器的信息
-
Host:指主机域名。主机域名结合请求行里的资源路径,可以得到一个完整的网址。第一个斜杠的前面的是域名,问号后的是参数,二者中间的就是资源路径,参看上面的例子
-
User-Agent:用来告知服务器客户端的相关信息。比如,请求是浏览器发出来的还是某个软件发出来的还是其他东西发出来的,如果是浏览器发出来的,类型是什么、版本是什么,等等。
curl命令行工具发出请求的User-Agent ->curl/7.77.0
Python的Requests库发出请求的User-Agent ->python-requests/2.25.1
Chrome发出请求的User-Agent ->Mozilla/5.0(Macintosh; Intel Mac OS X 10_15_7)
AppleWebKit/537.36(KHTML, like Gecko)Chrome/108.0.0.0 Safari/537.36 -
Accept:告诉服务器,客户端想要接收的响应数据是什么类型的,接收多种类型的话可以用逗号进行分隔
接受HTML ->text/html
接受JSON ->application/json
接受HTML和JSON ->text/html,application/json
接受任意类型 ->*/*
-
-
请求体:客户端传给服务器的其他任意数据。GET方法的请求体一般是空的。
-
-
响应的组成:
HTTP/1.1 200 OK # 状态行 Date: Fri, 27 Jan 2023 02:10:48 GMT # 响应头 Content-Type: text/html; charset=utf-8 # 响应头<!DOCTYPE html> # 响应体<head><title>首页</title></head> # 响应体<body><h1>呦呦呦</h1><p>哈喽!</p></body> # 响应体 </html> # 响应体
-
响应行:包含协议版本、状态码、状态消息
-
常见状态码:
-
200 OK // 客户端请求成功
-
301 Moved Permanently // 资源被永久移到新地址
-
400 Bad Request // 客户端不能被服务器所理解
-
401 Unauthorized // 请求未经授权
-
403 Forbidden // 服务器拒绝提供服务
-
404 Not Found // 请求资源不存在
-
500 Internal Sever Error // 服务器发生不可预期的错误
-
503 Server Unavailable // 服务器当前不能处理客户端的请求
2开头的表示成功。
3开头的表示重定向,需要进一步的操作。
4开头的表示客户端错误,比如请求里面有错误或者请求的资源无效等等
5开头的表示服务器错误,比如出现问题或正在维护
(网站HTTP 响应状态码 - HTTP | MDN (mozilla.org)可查询各种状态码的含义) -
-
-
响应头:包含告知客户端的信息
-
Date:生成响应的日期和时间\
-
Content-Type:返回内容的类型以及编码格式
-
-
响应体:服务器想给客户端的内容
-
实战演示1
import requests
response = requests.get('https://books.toscrape.com/') # 专门用来练习爬虫的网站
print(response) # <Response [200]> # 打印出来的是一个Response对象,包含了请求的响应内容
print(response.status_code, "\n==============================") # 200 # 打印出响应状态码 # 我们可以用response.text来获取响应内容的文本形式:
print(response.text, "\n==============================")# 我们也可以用response.content来获取响应内容的字节串形式:
print(response.content, "\n==============================")# 我们也可以用response.json()来获取响应内容的json形式# 可以用状态码来判断响应是否成功,也可以用Response对象的ok属性来判断:
if response.ok:print('请求成功')
else:print('请求失败')# 我们还可以用response.headers来获取响应头信息,它是一个字典。
# 我们还可以用response.cookies来获取响应的cookie信息,它是一个字典。
# 我们还可以用response.url来获取最终的url,它可能与请求url不同。
# 我们还可以用response.request来获取请求对象,它是一个PreparedRequest对象。
# 我们还可以用response.close()来关闭响应对象,释放资源。# 我们还可以用requests.post()、requests.put()、requests.delete()等方法来发送POST、PUT、DELETE请求。
# 这些方法的用法和requests.get()类似,只是需要传入不同的参数。
# 例如,requests.post('https://httpbin.org/post', data={'key': 'value'})可以发送一个POST请求,
# 并将参数data作为请求体发送给httpbin.org。
# requests.put('https://httpbin.org/put', data={'key': 'value'})可以发送一个PUT请求,
# 并将参数data作为请求体发送给httpbin.org。
# requests.delete('https://httpbin.org/delete')可以发送一个DELETE请求,
# 并将请求发送给httpbin.org。# 可以传入headers参数来设置请求头,headers的数据类型是一个字典,例如:
response = requests.get('https://httpbin.org/get', headers={'User-Agent': 'Mozilla/5.0'})
# 这样就可以模拟浏览器发送请求。把爬虫程序伪装成正常浏览器,可以避免被网站识别出来。
网页结构(三大技术要素:CSS、HTML、JS)
-
HTML:定义网页的结构和信息
<!DOCTYPE HTML> <!--这是一个声明文件类型的标签--> <html> <!--起始标签--><body> <!--body表示主题内容--><h1>这是一个标题</h1> <!--h1表示一级标题--><p>这是一段文字这是一段文字这是一段文字</p> <!--p表示文本段落--></body> </html> <!--闭合标签--> <!--起始标签和闭合标签及二者中间的内容构成一个html元素,html元素是html文档的根,所有其他元素都要放到这个元素里面-->
写一个.html后缀的文件,将其拖入浏览器顶部,就可以看到其在网页中是什么样子的了
在网页右击鼠标,选择“查看网页源代码”,就能知道网页源代码是什么样的了
在网页右击鼠标,选择“检查”,再点击左上角的“检查单个元素“标志,就可以对单个元素进行检查
-
网页标签:
-
标题:共有六级,
<h1>
-<h6>
。要与<title>
区分开来,<title>
指的是网页在顶部选项卡里显示的标题。 -
文本段落:
<p>
,不同的文本标签之间会默认进行换行,表示不同段落。如果直接在单个文本标签内换行,网页显示中并不会换行,会将这个换行(无论换了多少行)当作一个空格。 -
换行:
<br>
,无闭合标签。若想在单个<p>
标签内换行,必须在里面使用<br>
标签。<br>
的换行效果和多个<p>
形成的换行效果不一样,前者行距小,后者行距大。 -
加粗:
<b>
,包围要加粗的文本内容。 -
斜体:
<i>
-
下划线:
<u>
-
图片:
<img src="【指向图片的链接或路径】", width="500px", height="300px">
, 无闭合标签。 -
添加链接:
<a href="【url地址】"target="_self">我的主页</a>
。属性target表示链接的打开方式,可写可不写。target的值默认为"_self",表示直接在当前窗口跳转链接;也可以指定其为"_blank",表示在新窗口里打开。 -
容器:
<div>
,<span>
。前者是块状元素,一行最多只能有一个。后者是内联元素,一行中可以有多个。二者都用于包裹其他元素,用于对其他元素的集中处理,比如集中设置背景颜色等样式。 -
有序列表:
<ol>
。列表里的每一项元素还需要用<li>
来包裹。每一项元素前面有数字来进行排序。 -
无序列表:
<ul>
。每一项元素前是一个点号,没有数字来进行排序。 -
表格:
<table>
表示表格,里面要有其他的子元素标签。如:-
<thead>
:表示表格的头部,一般是表格的第一行。 -
<tbody>
:表示表格的主体。 -
<tr>
:放在前两者的内部,定义表格行。 -
<td>
:放在前者内部,定义一个个单元格,表示一个个数据。
可以给表格加上一些属性,如:
<table border="1">
,这样表格就会有边框。 -
-
class属性:可以用在任何标签上,帮助我们分组。比如,一个网页上可能有多个文本段落,我们可以通过
<p class="content">给岁月以文明</p>
、<p class="review">五星好评</p>
将其分为文章和用户评论。其在结合CSS和JS时会很有用。
-
-
-
CSS:定义网页的样式
-
JS:定义用户和网页的交互逻辑
网页标签实践
<!DOCTYPE html>
<html><head><title>这是我的网页标题</title></head><body><h1>这是一个一级标题</h1><h2>这是一个二级标题</h2><h3>这是一个三级标题</h3><div style="background-color: yellow;"><h4>这是一个四级标题</h4><h5>这是一个五级标题</h5><h6>这是一个六级标题</h6></div><h7>这是一个<span style="color: red;">错误</span>的七级标题,<span style="background-color: rgb(12, 106, 12);">浏览器</span>不支持,所以会显示为<span style="color: blue;">正常的文本</span></h7><p>这是一个文本段落,和上面的七级标题是一样大小的</p><p>当该html文件发生更改(并保存)时,只要<b>浏览器</b>不缓存,就会<u>自动更新</u>显示,不需要<i>手动刷新</i>;<br>但是如果浏览器缓存了该文件,则需要手动刷新才能看到更新后的效果。</p><img src="https://p1.ssl.qhmsg.com/t0143b426aee3bb03cb.jpg" width="300" height="300"><br><a href="https://www.baidu.com" target="_blank">在新窗口打开百度</a><br><a href="https://www.baidu.com">在当前窗口打开百度</a><br><ol><li>第一项</li><li>第二项</li><li>第三项</li></ol><ul><li>第一项</li><li>第二项</li><li>第三项</li></ul><table border="1"><tr><th>姓名</th><th>性别</th><th>年龄</th></tr><tr><td>张三</td><td>男</td><td>20</td></tr><tr><td>女</td><td>25</td></tr><tr><td>王五</td><td>男</td><td>30</td></tr></table><br><table border="5"><thead><th>姓名</th><td>性别</td><td>年龄</td></thead><tbody><tr><td>张三</td><td>男</td><td>20</td></tr><tr><td>女</td><td>25</td></tr><tr><td>王五</td><td>男</td><td>30</td></tr></tbody></table></body>
</html>
解析网页结构
用Python第三方库:Beautiful Soup
from bs4 import BeautifulSoup
import requestsurl = "http://books.toscrape.com/"
response = requests.get(url)
text = response.text
soup = BeautifulSoup(text, "html.parser") # 第二个参数是解析器,这里使用html.parser# print(soup.p) # 输出第一个<p>标签的内容
# print(soup.find_all("p")) # 输出所有<p>标签的内容# print(soup.img) # 输出第一个<img>标签的内容
# print(soup.find_all("img")) # 输出所有<img>标签的内容# 找价格
all_prices = soup.find_all("p", attrs={"class": "price_color"}) # 第二额参数是属性,类型为字典,这里查找所有class为price_color的<p>标签
for price in all_prices:print(price) # 输出所有<p>标签中表示价格的<p>标签print(price.text) # 只输出价格即字符串内容print(price.string) # 等价于上一行,输出价格即字符串内容print(price.string[2:]) # 输出价格的数字部分(即索引值从2开始的部分)# 找书名
all_titles = soup.find_all("h3") # 查找所有<h3>标签
for title in all_titles:all_links = title.find_all("a") # 在每个<h3>标签中查找所有<a>标签for link in all_links:print(link.text) # 输出所有<a>标签中的文本内容,即书名# 结果
<p class="price_color">£51.77</p>
£51.77
£51.77
51.77
<p class="price_color">£53.74</p>
£53.74
£53.74
53.74
<p class="price_color">£50.10</p>
£50.10
£50.10
50.10
<p class="price_color">£47.82</p>
£47.82
£47.82
47.82
<p class="price_color">£54.23</p>
£54.23
£54.23
54.23
<p class="price_color">£22.65</p>
£22.65
£22.65
22.65
<p class="price_color">£33.34</p>
£33.34
£33.34
33.34
<p class="price_color">£17.93</p>
£17.93
£17.93
17.93
<p class="price_color">£22.60</p>
£22.60
£22.60
22.60
<p class="price_color">£52.15</p>
£52.15
£52.15
52.15
<p class="price_color">£13.99</p>
£13.99
£13.99
13.99
<p class="price_color">£20.66</p>
£20.66
£20.66
20.66
<p class="price_color">£17.46</p>
£17.46
£17.46
17.46
<p class="price_color">£52.29</p>
£52.29
£52.29
52.29
<p class="price_color">£35.02</p>
£35.02
£35.02
35.02
<p class="price_color">£57.25</p>
£57.25
£57.25
57.25
<p class="price_color">£23.88</p>
£23.88
£23.88
23.88
<p class="price_color">£37.59</p>
£37.59
£37.59
37.59
<p class="price_color">£51.33</p>
£51.33
£51.33
51.33
<p class="price_color">£45.17</p>
£45.17
£45.17
45.17
A Light in the ...
Tipping the Velvet
Soumission
Sharp Objects
Sapiens: A Brief History ...
The Requiem Red
The Dirty Little Secrets ...
The Coming Woman: A ...
The Boys in the ...
The Black Maria
Starving Hearts (Triangular Trade ...
Shakespeare's Sonnets
Set Me Free
Scott Pilgrim's Precious Little ...
Rip it Up and ...
Our Band Could Be ...
Olio
Mesaerion: The Best Science ...
Libertarianism for Beginners
It's Only the Himalayas
爬虫实战(爬豆瓣前250的电影)
import requests
from bs4 import BeautifulSoup
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0'
}
response = requests.get('https://movie.douban.com/top250', headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
titles = soup.find_all("span", class_="title")
i = 0
for title in titles:# print(title.text) # 输出电影名(包括原标题)if "/" not in title.string:i+=1print(i, ".", title.string) # 输出电影名(去除原标题)print("========================================================================")# 以上操作只能获得第一页的内容,也即前25部电影的名称。
# 点击到第二页我们会发现,其网址的参数信息变化了,start变成了25,可以以这个为基础,继续请求第二页的内容。
# 我们可以定义一个函数,传入页码,返回该页的电影名称列表,然后再循环调用这个函数,获取所有电影名称。
# 具体的实现方法可以参考如下代码:# 定义一个函数,传入页码,返回该页的电影名称列表
def get_movie_names(page):headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0'}url = 'https://movie.douban.com/top250?start=' + str((page-1)*25)response = requests.get(url, headers=headers)soup = BeautifulSoup(response.text, 'html.parser')titles = soup.find_all("span", class_="title")movie_names = []for title in titles:if "/" not in title.string:movie_names.append(title.string)return movie_names# 循环调用这个函数,获取所有电影名称
movie_names = []
for i in range(1, 11):movie_names += get_movie_names(i)# 输出所有电影名称
# for i, name in enumerate(movie_names):
# print(i+1, ".", name)
j = 1
for name in movie_names:print(j, ".", name)j += 1# 结果如下:
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 . 寻梦环游记
========================================================================
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 . 活着
30 . 哈利·波特与魔法石
31 . 蝙蝠侠:黑暗骑士
32 . 指环王3:王者无敌
33 . 我不是药神
34 . 乱世佳人
35 . 飞屋环游记
36 . 素媛
37 . 哈尔的移动城堡
38 . 十二怒汉
39 . 让子弹飞
40 . 何以为家
41 . 摔跤吧!爸爸
42 . 海蒂和爷爷
43 . 猫鼠游戏
44 . 天空之城
45 . 鬼子来了
46 . 少年派的奇幻漂流
47 . 钢琴家
48 . 指环王2:双塔奇兵
49 . 大话西游之月光宝盒
50 . 闻香识女人
51 . 死亡诗社
52 . 绿皮书
53 . 大闹天宫
54 . 罗马假日
55 . 黑客帝国
56 . 指环王1:护戒使者
57 . 天堂电影院
58 . 教父2
59 . 狮子王
60 . 辩护人
61 . 饮食男女
62 . 搏击俱乐部
63 . 本杰明·巴顿奇事
64 . 美丽心灵
65 . 穿条纹睡衣的男孩
66 . 窃听风暴
67 . 情书
68 . 两杆大烟枪
69 . 音乐之声
70 . 西西里的美丽传说
71 . 看不见的客人
72 . 哈利·波特与死亡圣器(下)
73 . 阿凡达
74 . 拯救大兵瑞恩
75 . 小鞋子
76 . 飞越疯人院
77 . 功夫
78 . 沉默的羔羊
79 . 布达佩斯大饭店
80 . 禁闭岛
81 . 蝴蝶效应
82 . 哈利·波特与阿兹卡班的囚徒
83 . 致命魔术
84 . 心灵捕手
85 . 超脱
86 . 低俗小说
87 . 摩登时代
88 . 春光乍泄
89 . 海豚湾
90 . 喜剧之王
91 . 美国往事
92 . 致命ID
93 . 杀人回忆
94 . 哈利·波特与密室
95 . 红辣椒
96 . 加勒比海盗
97 . 一一
98 . 七宗罪
99 . 狩猎
100 . 唐伯虎点秋香
101 . 7号房的礼物
102 . 被嫌弃的松子的一生
103 . 蝙蝠侠:黑暗骑士崛起
104 . 甜蜜蜜
105 . 爱在黎明破晓前
106 . 第六感
107 . 超能陆战队
108 . 请以你的名字呼唤我
109 . 入殓师
110 . 重庆森林
111 . 断背山
112 . 剪刀手爱德华
113 . 幽灵公主
114 . 寄生虫
115 . 爱在日落黄昏时
116 . 勇敢的心
117 . 菊次郎的夏天
118 . 借东西的小人阿莉埃蒂
119 . 未麻的部屋
120 . 消失的爱人
121 . 无人知晓
122 . 时空恋旅人
123 . 阳光灿烂的日子
124 . 完美的世界
125 . 倩女幽魂
126 . 天使爱美丽
127 . 小森林 夏秋篇
128 . 哈利·波特与火焰杯
129 . 侧耳倾听
130 . 驯龙高手
131 . 茶馆
132 . 幸福终点站
133 . 教父3
134 . 怪兽电力公司
135 . 一个叫欧维的男人决定去死
136 . 新世界
137 . 玩具总动员3
138 . 傲慢与偏见
139 . 小森林 冬春篇
140 . 被解救的姜戈
141 . 萤火之森
142 . 釜山行
143 . 神偷奶爸
144 . 色,戒
145 . 头脑特工队
146 . 九品芝麻官
147 . 哪吒闹海
148 . 告白
149 . 玛丽和马克思
150 . 喜宴
151 . 大鱼
152 . 模仿游戏
153 . 头号玩家
154 . 花样年华
155 . 射雕英雄传之东成西就
156 . 七武士
157 . 我是山姆
158 . 血战钢锯岭
159 . 惊魂记
160 . 阳光姐妹淘
161 . 恐怖直播
162 . 你的名字。
163 . 黑客帝国3:矩阵革命
164 . 三块广告牌
165 . 电锯惊魂
166 . 心迷宫
167 . 达拉斯买家俱乐部
168 . 疯狂原始人
169 . 谍影重重3
170 . 小丑
171 . 背靠背,脸对脸
172 . 上帝之城
173 . 英雄本色
174 . 心灵奇旅
175 . 风之谷
176 . 绿里奇迹
177 . 爱在午夜降临前
178 . 海街日记
179 . 纵横四海
180 . 卢旺达饭店
181 . 疯狂的石头
182 . 2001太空漫游
183 . 无间道2
184 . 记忆碎片
185 . 雨中曲
186 . 小偷家族
187 . 无敌破坏王
188 . 岁月神偷
189 . 忠犬八公物语
190 . 荒蛮故事
191 . 冰川时代
192 . 牯岭街少年杀人事件
193 . 爆裂鼓手
194 . 恐怖游轮
195 . 东京教父
196 . 魔女宅急便
197 . 大佛普拉斯
198 . 贫民窟的百万富翁
199 . 遗愿清单
200 . 东邪西毒
201 . 末路狂花
202 . 你看起来好像很好吃
203 . 可可西里
204 . 源代码
205 . 城市之光
206 . 黑天鹅
207 . 海边的曼彻斯特
208 . 疯狂的麦克斯4:狂暴之路
209 . 波西米亚狂想曲
210 . 真爱至上
211 . 雨人
212 . 青蛇
213 . 爱乐之城
214 . 初恋这件小事
215 . 芙蓉镇
216 . 终结者2:审判日
217 . 人工智能
218 . 虎口脱险
219 . 恋恋笔记本
220 . 新龙门客栈
221 . 无耻混蛋
222 . 花束般的恋爱
223 . 罗生门
224 . 高山下的花环
225 . 崖上的波妞
226 . 千钧一发
227 . 彗星来的那一夜
228 . 哈利·波特与死亡圣器(上)
229 . 白日梦想家
230 . 萤火虫之墓
231 . 黑客帝国2:重装上阵
232 . 奇迹男孩
233 . 火星救援
234 . 二十二
235 . 战争之王
236 . 血钻
237 . 哈利·波特与凤凰社
238 . 步履不停
239 . 千年女优
240 . 大红灯笼高高挂
241 . 房间
242 . 魂断蓝桥
243 . 谍影重重2
244 . 蜘蛛侠:平行宇宙
245 . 弱点
246 . 谍影重重
247 . 阿飞正传
248 . 朗读者
249 . 隐藏人物
特与死亡圣器(上)
229 . 白日梦想家
230 . 萤火虫之墓
231 . 黑客帝国2:重装上阵
232 . 奇迹男孩
233 . 火星救援
234 . 二十二
235 . 战争之王
236 . 血钻
237 . 哈利·波特与凤凰社
238 . 步履不停
239 . 千年女优
240 . 大红灯笼高高挂
241 . 房间
242 . 魂断蓝桥
243 . 谍影重重2
244 . 蜘蛛侠:平行宇宙
245 . 弱点
246 . 谍影重重
247 . 阿飞正传
248 . 朗读者
249 . 隐藏人物
250 . 再次出发之纽约遇见你
下一步学习什么
-
正则表达式
python的正则表达式库:re
-
多线程
Python多线程库:threading
-
数据库
-
数据分析