爬虫又称网络蜘蛛、网络机器人。本质就是程序模拟人使用浏览器访问网站,并将需要的数据抓取下来。爬虫不仅能够使用在搜索引擎领域,在数据分析、商业领域都得到了大规模的应用。
URL
每一个URL指向一个资源,可以是一个html页面,一个css文档,一个js文件,一张图片等等。
URL的格式:protocol://hostname[:port]/path[?query]
protocol:网络传输协议
hostname:存放资源的服务器的域名或IP地址
port:是一个可选的整数,取值范围是0-65535。如果被省略了,默认http端口为80,https的端口是443。
path:路由地址,一般用来表示主机上的一个目录或文件地址,由零个或多个/符号隔开的字符串,路由地址决定了服务端如何处理这个请求。
query:从?开始到它们之间的部分就是参数,又称搜索部分或者查询字符串。
HTTP协议
HTTP(超文本传输协议)主要作用是让服务端和客户端之间进行数据交互(相互传输数据)。
HTTPS(安全超文本传输协议)是HTTP协议的安全版,对传输数据进行加密。
HTTP请求
请求类别:HTTP协议中定义了八种请求方法。主要了解两种:get和post请求。
get请求:从服务器获取数据下来,并不会对服务器资源产生任何影响的时候使用get请求。
post请求:向服务端发送数据(登录)、上传文件等,会对服务器资源产生影响时使用post请求。
请求头
User-Agent:请求载体的身份标识。在请求一个网页的时候,服务器通过这个参数就可以知道这个请求是由那种浏览器发送的。如果我们是通过爬虫发送请求,那么我们的User-Agent就是Python。不过对于有反爬虫机制的网站来说,这样就可以轻易的判断这个请求时爬虫。因此,我们要设置这个值为一些浏览器的值,来伪装我们的爬虫。
Cookie:对应的是一个用户的信息,http协议是无状态的。也就是同一个人发送了两次请求,服务器没有能力知道这两个请求是否来自同一个人,因此这时候就用cookie来做标识。
请求体:提交的内容
HTTP响应
响应行:反馈基本的响应情况
常见的响应状态码:
200:请求正常,服务器正常的返回数据
302:临时重定向。比如在访问一个需要登录的页面的时,而此时没有登录,就会重定向到登陆页面。
400:请求的url在服务器上找不到。换句话说就是请求url错误。
403:服务器拒绝访问,权限不够。
500:服务器内部错误。
响应头:对响应内容的描述。
Content-Length:服务器通过这个头,告诉浏览器回送数据的长度。
Content-Type: 服务器通过这个头,告诉浏览器回送数据的类型。
编写爬虫的基础流程
1.确定你要获取的数据,确定需要爬取的URL地址。
网页上数据有的是通过js动态加载出来的。使用Ajax。
2.使用请求模块向URL地址发出请求,并得到响应内容。
通过代码去发送请求
3.从响应内容中提取所需数据。
4.存储
在python的html后缀名下的文件内中写:
<script>
let xhr = new XMLHttpRequest()
xhr.open('GET', 'http://yu.ming(全是数字的那一串)/curl/getIp')
//发送请求
xhr.send()
xhr.onload = function(){
//json
let data = JSON.parse(xhr.reponse)
let span1 = document.createElement('span')
let span2 = document.createElement('span')
span1.innerHTML = 'ip:' + data.returnCitySN.ip + '<br>'
span2.innerHTML = '地址' + data.returnCitySN.Country + '<br>'
document.body.appendChild(span1)
document.body.appendChild(span2)
}
</script>
requests模块
在cmd窗口下pip install requests来导入第三方模块,或者在pycharm内file的setting下Python Interpreter内进行下载。
requests模块的使用
1.requests.get():表示向网站发送GET请求,获取页面响应对象。
语法:
response=requests.get(url,headers=headers,params)
url:要抓取的url地址
headers:用于包装请求头信息
params:请求时携带的查询字符串参数
2.HttpResponse响应对象:我们使用requests模块向一个URL发起请求后会返回这样的对象。
响应对象属性:
text:获取相应内容字符串类型
content:获取响应内容bytes类型(抓取图片、音频、视频文件)
encoding:查看或指定响应字符编码
request.headers:查看响应对应的请求头
cookies:获取响应的cookie,经过set-cookie动作,返回coookieJar类型
json():将json字符串类型的响应内容转换为python对象
import requests
url = 'https://www.maoyan.com/board/6?timeStamp=1707033337406&channelId=40011&index=7&signKey=05c5030979de1a94fc40756853de3ca4&sVersion=1&webdriver=false&offset=0'
# 使用requests 帮我们发送一个get请求
response = requests.get(url) # get函数内放置url参数,获取响应内容并用一个变量来接收
print(response.request.headers) # 获取请求头
print(response.text) # 获取响应内容(可能会被反爬虫阻拦获取不到。此时就需要伪装一下了)
3.发送带header的请求
import requests
url = 'https://www.jd.com/?cu=true&utm_source=baidu-pinzhuan&utm_medium=cpc&utm_campaign=t_288551095_baidupinzhuan&utm_term=0f3d30c8dba7459bb52f2eb5eba8ac7d_0_0210197b670445ddbba4fb6fe8baceb0'
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
}
response = requests.get(url, headers=header)
print(response.text)
'''
正则的定义:按照一定的规则,在字符串里面匹配要找的内容
如何使用正则:导入re文件
'''
import re
# findall:找到所有满足条件的数据,得到一个列表
re.findall()
# . 匹配一个任意字符 除了换行
# re.S 使. 可以匹配到换行符
re.findall('a.','aba\naa',re.S)
# * 出现0次或多次
re.findall('a*','aba\naa')
# .*贪婪匹配(尽量多匹配)
html = '<div></div>' print(re.findall('<.*>',html))
# 得到结果:['<div></div>']
# .*?非贪婪匹配(尽量少匹配)
html = '<div></div>' print(re.findall('<.*?>',html))
# 得到结果:['<div>', '</div>']
# 把想要的东西加括号,提取出来
html = '<div>XX</div>'
print(re.findall('<div>(.*?)</div>', html)) # ['XX']
关于完整使用:
import requests
base_url = 'https://movie.douban.com/chart'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
}
def get_html(url):
# 发送请求功能
response = requests.get(url, headers=headers)
return response.text
def parse_html(html):
# 提取数据功能
r_list = re.findall('<div class="pl2">.*?>\n(.*?)/.*?</a>.*?<span class="rating_nums">(.*?)</span>', html, re.S)
return r_list
def save(data_list):
# 存储数据功能
for data in data_list:
name = data[0].strip() # 去除两边空格
num = data[1]
print(name, num)
print('-'*30)
html = get_html(base_url)
# print(html)
data_list = parse_html(html)
save(data_list)
结果:
怪物 8.6
------------------------------
荒野 5.7
------------------------------
涉过愤怒的海 7.2
------------------------------
枯叶 7.9
------------------------------
坠落的审判 8.5
------------------------------
爆裂点 5.7
------------------------------
再见,李可乐 6.3
------------------------------
杂种 8.2
------------------------------
刀尖 5.3
------------------------------
花月杀手 7.3
------------------------------
将存储数据到mysql内
首先导入第三方模块pymysql
写法一:
import pymysql
# 导入模块
# 建立数据库的链接
db = pymysql.connect(
host='127.0.0.1',
port=3306,
database='douban',
user='root',
password='123456',
charset='utf8'
)
# 创建数据库 create database douban;(终端要输入的,否则会报错)
# 创建游标对象 通过游标对象去操作
cur = db.cursor()
# 执行操作
sql = 'insert into movie_info(name, num) values("%s", "%f")' % ('怪物', 8.6)
cur.execute(sql)
db.commit()
'''
创建表的语法:
create table movie_info(
id int primary key auto_increment,
name varchar(20),
num float(5)
);
'''
# 关闭游标对象
cur.close()
# 关闭连接
db.close()
注意:
- 创建数据库和创建表的代码要在cmd的mysql内部进行。
- 在创建表之前先使用表:use douban;
- 小数记得用 %f 哦.
写法二:
全部写入进该表中:
import re
import requests
import pymysql
# 建立数据库的链接
db = pymysql.connect(
host='127.0.0.1',
port=3306,
database='douban',
user='root',
password='123456',
charset='utf8'
)
cur = db.cursor()
sql = 'insert into movie_info(name, num) values("%s", "%s")'
base_url = 'https://movie.douban.com/chart'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
}
def get_html(url):
# 发送请求功能
response = requests.get(url, headers=headers)
return response.text
def parse_html(html):
# 提取数据功能
r_list = re.findall('<div class="pl2">.*?>\n(.*?)/.*?</a>.*?<span class="rating_nums">(.*?)</span>', html, re.S)
return r_list
def save(data_list):
# 存储数据功能
for data in data_list:
name = data[0].strip() # 去除两边空格
num = data[1]
print(name, num)
li = [name, num]
cur.execute(sql, li)
db.commit()
print('-'*30)
html = get_html(base_url)
# print(html)
data_list = parse_html(html)
save(data_list)
# 关闭游标对象
cur.close()
# 关闭连接
db.close()
注意:前面已经写入的内容要进行删除,不然会报错的(主键的唯一性)。
import re
import requests
import pymysql
# 建立数据库的链接
db = pymysql.connect(
host='127.0.0.1',
port=3306,
database='douban',
user='root',
password='123456',
charset='utf8'
)
cur = db.cursor()
sql = 'insert into movie_info(name, num) values("%s", "%f")'
base_url = 'https://movie.douban.com/top250?start={}&filter=' # {}切换页数
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
}
def get_html(url):
# 发送请求功能
response = requests.get(url, headers=headers)
return response.text
def parse_html(html):
# 提取数据功能
r_list = re.findall('<div class="pl2">.*?>\n(.*?)/.*?</a>.*?<span class="rating_nums">(.*?)</span>', html, re.S)
save(r_list)
def save(data_list):
# 存储数据功能
for data in data_list:
name = data[0].strip() # 去除两边空格
num = data[1]
print(name, num)
li = [name, num]
cur.execute(sql, li)
db.commit()
print('-'*30)
# 对爬取的内容找规律
for start in range(0, 226, 25):
url = base_url.format(start)
print(url)
html = get_html(url)
parse_html(html)
cur.close()
db.close()
使用json来提取数据
import requests
import json
url = 'https://spa1.scrape.center/api/movie/?limit=10&offset=0'
response = requests.get(url)
json_data = response.json() # 用json对象来进行接收
for data in json_data["results"]:
print(data["name"])
print(data["categories"])
print('-'*30)
换页提取:
第一种方式:
import re
import requests
base_url = 'https://www.maoyan.com/board/4?offset={}'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
}
def get_html(url):
'''
通过requests模块发送get请求
:param url: 给那个url发送请求
:return: html代码
'''
response = requests.get(url, headers=headers)
print(response.url)
return response.text
def parse_html(html):
'''
提取数据的函数
:param html: 在那个代码中寻找
'''
r_list = re.findall('<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)</p>', html, re.S)
save(r_list)
def save(data_list):
for data in data_list:
li = [
data[0],
data[1].split(':')[1].strip(),
data[2].split(':')[1].strip(),
]
print(li)
for offset in range(0, 91, 10):
url = base_url.format(offset)
html = get_html(url=url)
parse_html(html)
print('-'*100)
第二种方式:
import re
import requests
base_url = 'https://www.maoyan.com/board/4'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
}
params = {
"offset": 0
}
def get_html(url):
'''
通过requests模块发送get请求
:param url: 给那个url发送请求
:return: html代码
'''
response = requests.get(url, headers=headers, params=params)
print(response.url)
return response.text
def parse_html(html):
'''
提取数据的函数
:param html: 在那个代码中寻找
'''
r_list = re.findall('<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)</p>', html, re.S)
save(r_list)
def save(data_list):
for data in data_list:
li = [
data[0],
data[1].split(':')[1].strip(),
data[2].split(':')[1].strip(),
]
print(li)
for offset in range(0, 91, 10):
params['offset'] = offset
html = get_html(url=base_url)
parse_html(html)
print('-'*100)
https://curlconverter.com/#
代码复制copy的代码可自动生成
爬取音乐
import requests
response = requests.get('https://音乐所在网址')
print("请求成功")
song_data = response.content
with open('疑心病.mp3', 'wb')as f:
f.write(song_data)
会添加到pycharm内,拖拽到桌面上即可。