上一节我们讲了浏览器的基础操作,这节来了解一下网站爬虫。
什么是网站爬虫
- 简单来讲,爬虫就是一个探测机器,它的基本操作就是模拟人的行为去各个网站溜达,点点按钮,查查数据,或者把看到的信息背回来。就像一只虫子在屋里不停地爬来爬去。
用处
爬虫的应用很广泛,常见的有以下几种:
- 从各大网站上爬取所需要的图片,资源等(这里涉及到一个权限的问题,如果这些爬下来的资源自己用是没有任何问题的,但是如果你通过其来搞盈利,是会被版权方追究责任的);
- 抢票软件,每逢节假日售票网站总有几个崩的;
出行行业中爬虫的占比最高(20.87%)。在出行的爬虫中,有 89.02% 的流量都是冲着 12306 去的。每次我们买票出现的验证码可以阻挡部分爬虫系统,剩下的爬虫当然是更高阶的,通过机器学习
记忆了这些验证码图片,下次再遇到这些图片就知道了。
这里的原理类似于占位,爬虫程序不停的刷新网页,当查询到有余票的时候就会由A下单占位。由此衍生了“黄牛”,你在黄牛那里买了票,提供了你的下单信息B,会有系统取消订单A,在用你的信息B来下单。这种就是恶意爬虫。
当然,如果你学会了爬虫之后,每次抢票可以自己写一个爬虫程序,不用再在其它网站购买VIP来加速了,真香警告!
准备
首先,我们在进行爬虫之前需要知道以下的知识:
- 网站爬虫实际上就是模拟了网页的访问,关于浏览器的基础知识,上节我们已经讲过了;
- HTTP请求,访问网页是通过HTTP请求来实现的,
- 客户端向服务器发送一个HttpRequest请求,(client - > Server : HttpRequest)
- 服务器收到请求之后返回Response信息给客户端 (Server - > client:Response)
- 常见的HttpRequest方法:
- get请求 — 绝大多数的网页访问
- post请求 — 用户需要传递一些数据给服务器,服务器接收后 ,处理数据返回给客户端
知道了这些基础知识,我们来看一下基本的步骤:
步骤
- HttpRequest 工具模拟HTTP请求,接收返回的文本
用于请求的包: requests
安装:pip install requests
#header 请求头参数
user-agent:
referer: - 对接收的文本进行筛选,获取想要的内容
用户筛选文本的包 bs4 和 lxml
安装:
pip install bs4
pip install lxml
实战:
我们以https://www.ilync.cn/org/6818_d_0_0_-1_-1_0_1网站为例,爬取课程名称,图片,课程id,价格等信息
打开控制台到Nextwork,选中DOC, 看到下面这个请求,有请求地址和请求方法GET,在请求头Request Headers里有两个重要参数,在我们模拟请求的时候也要带过去
Referer
:告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理
User Agent
:用户代理,向访问网站提供你所使用的浏览器类型及版本、操作系统及版本、浏览器内核、等信息的标识。通过这个标识,用户所访问的网站可以显示不同的排版从而为用户提供更好的体验或者进行信息统计
- 首先安装我们需要的包 requests、bs4 、lxml
pip install requests
pip install bs4
pip install lxml
安装完可以用 pip show bs4 进行查看, 会展示包的相关信息
- 导入我们需要的包:
import requests # 请求
from bs4 import BeautifulSoup # 筛选文本
import lxml
- 定义一个请求方法,获取网页内容
def get_content(url):
#header 模拟请求头
header = {
'Referer': "https://www.ilync.cn/",
'Host': 'www.ilync.cn',
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
}
response = requests.get(url,headers = header)
response_text = response.content.decode("utf-8") #对返回文本进行utf-8编码
# print(response_text) 查看返回的内容
return response_text
在改网站我们点击翻页,观察请求的地址可以发现,请求的地址前面部分是固定的,所以我们定义一个基础的base_url
- 调用这个方法:
# 定义一个url
base_url = 'https://www.ilync.cn/org/6818_d_0_0_-1_-1_0_'
get_content(base_url + str(1)) # 获取第一页的文本
我们可以看到返回的是一个html文本,里面有很多我们需要的信息,那么接下来我们需要对获得的文本进行筛选处理:
- 对文本进行筛选处理:
前面说我们需要的是课程的图片,id,标题,价格信息,在浏览器里查看对应的元素,发现所有我们所需的内容都在这个class名是course-list-wrap 的 div [1] 里,div [1] 下列表都有一个class名为grid-cell的div[2]里,那么我们可以根据这个进行筛选:
定义一个筛选文本的方法:
"""根据文本分析内容"""
def get_soure(content:str):
soup = BeautifulSoup(content,'lxml') # 引入的lxml包 实例化一个对象
# 第一次进行筛选
# 所得到的的是一个列表 , 我们需要的在列表的第一个
first_filter = soup.find_all('div',class_ = 'course-list-wrap')[0]
# 第二次筛选
second_filter = first_filter.find_all('div',class_ = 'grid-cell')
# print(second_filter)
# 调用
content = get_content(base_url + str(1))
get_soure(content)
这里我们打印一下看看第二次筛选到的内容,是一个列表,列表里每一项含对应的信息,这里的信息我们看浏览器里的更为清晰:
图5:
我们通过上面筛选过的列表获取对应的值:
# 需要用正则表达式对获取的数据进行美化,引入re包
import re
# get_soure 函数中:
infos = [] #定义一个列表来存放获取到的值
for one in second_filter:
temp_dict = {} # 定义临时字典变量
img = one.find('img').attrs['src']
title = one.find('img').attrs['title']
price = one.find('div',class_='course-price').text
price = re.sub(r'\s','',price) # 去除制表符、换行符
temp_dict['title'] = re.sub(r'\xa0',' ',title) # 空格转换
temp_dict['img'] = img
temp_dict['price'] = price
infos.append(temp_dict)
print(infos)
这样我们就得到了所有我们想要的数据了
- 多页请求
上面的是第一页,网站上我们看到是可以分页的,那么我们怎么去获取所有页码的信息呢?
查看页面元素,可以看到有一个条数显示,如下:
那么我们就可以获取到总的条数了,每页24条,通过计算就知道了总共多少页,定义一个计算页码的函数:
# 获取总页码
import math # 引入math
def get_total_page(begin_page:int):
content = get_content(base_url + str(begin_page))
soup = BeautifulSoup(content,'lxml') #实例化一个对象
total = soup.find('input',id = 'countCourseNum').attrs['value']
return math.ceil(int(total)/25) # 向上取整
# 调用一下
total_page = get_total_page(1)
print(total_page)
- 文本写入文件
有了总页码,也有每个页面获取数据的方法,那我们就可以循环来获得所有数据了,在结合我们之前学过的把文本写入文件:
fp = open("ilync.txt",mode="a",encoding="utf-8")
total_page = get_total_page(1)
print(total_page) # 总条数
for num in range(1,total_page+1):
content = get_content(base_url + str(num)) #请求获取文本
infos = get_soure(content) #数据整理过滤
# 写入文件
for line in infos:
total += 1
fp.write(str(line)+'\n'+'='*10+'\n') # 转换为str 写入文件
fp.close()
下面附上完整的代码文件:
import requests
from bs4 import BeautifulSoup
import lxml
import re
import math
base_url = 'https://www.ilync.cn/org/6818_d_0_0_-1_-1_0_'
# 发起请求,获取网站内容
def get_content(url):
#header 模拟请求头 Referer 来源
header = {
'Referer': "https://www.ilync.cn/",
'Host': 'www.ilync.cn',
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
}
response = requests.get(url,headers = header)
response_text = response.content.decode("utf-8") #返回文本进行utf-8编码
# print(response_text)
return response_text
# 获取总页码
def get_total_page(begin_page:int):
content = get_content(base_url + str(begin_page))
soup = BeautifulSoup(content,'lxml') #实例化一个对象
total = soup.find('input',id = 'countCourseNum').attrs['value']
return math.ceil(int(total)/24)
"""根据文本分析内容"""
def get_soure(content:str):
soup = BeautifulSoup(content,'lxml') #实例化一个对象
# 第一次进行筛选
first_filter = soup.find_all('div',class_ = 'course-list-wrap')[0]
# 第二次筛选
second_filter = first_filter.find_all('div',class_ = 'grid-cell')
#循环获取所需的图片、标题、价格、
infos = []
for one in second_filter:
temp_dict = {}
img = one.find('img').attrs['src']
title = one.find('img').attrs['title']
price = one.find('div',class_='course-price').text
price = re.sub(r'\s','',price) # 去除制表符、换行符
temp_dict['title'] = re.sub(r'\xa0',' ',title) # 空格转换
temp_dict['img'] = img
temp_dict['price'] = price
infos.append(temp_dict)
# print(infos)
return infos
fp = open("ilync.txt",mode="a",encoding="utf-8")
total_page = get_total_page(1)
print(total_page)
for num in range(1,total_page+1):
content = get_content(base_url + str(num)) #请求获取文本
infos = get_soure(content) #数据整理过滤
# 写入文件
for line in infos:
fp.write(str(line)+'\n'+'='*10+'\n') # 转换为str 写入文件
fp.close()
以上就是我们今天所有的内容,留一个扩展,
- 怎么把图片存储到本地的文件夹下?
- 获取列表里每条数据的详情页信息
- 保存数据为Excel