一 爬虫
1.1 认识爬虫
1.什么是爬虫 - 获取网络数据(公开的网络)
网络数据来源:网站对应的网页、手机APP
2.爬虫的基本流程
第一步:获取网络数据(requests、selenium)
第二步:解析数据-从获取的网络数据中提取有效的数据(正则、bs4、lxml)
第三步:保存数据(csv、excel、数据等)
3.requests - 获取网络数据的第三方库(基于http或者https协议的网络请求)
爬虫使用requests的两个常景:直接请求网页地址、对提供网页数据的数据接口发送请求
1)对目标网页直接发送请求
requests.get(网页地址) - 获取指定网页的数据返回一个响应对象
import requests
response= requests.get('https://cd.zu.ke.com/zufang')
print(response) #<Response [200]> 200-请求成功
获取响应的状态码 status_code
print(response.status_code)
if response.status_code!=200:
pass
获取响应头
print(response.headers)
请求内容(返回的真正有用的数据)
response.content - 二进制类型的数据(图片、视频、音频等,例如图片下载)
response.text - 字符串类型的数据(网页)
response.json() - 对请求内容做完json解析后的数据(json数据接口)
print(response.content)
4.html是以标签为单位来给网页提供内容的。
不同的标签可以提供不同的内容。
- 标签的语法结构(重要!):
1)双标签:<标签名 属性名1=属性值1 属性名2=属性值2 …>标签内容</标签名>
2)单标签:<标签名 属性名1=属性值1 属性名2=属性值2 …> 或者 <标签名 属性名1=属性值1 属性名2=属性值2 …/>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>YuTing的网站</title>
<link rel="icon" href="img/长城.png">
</head>
<body>
<h1>学生信息录入</h1>
<img src="https://img1.baidu.com/it/u=3002324397,2878731521&fm=253&fmt=auto&app=138&f=JPEG?w=640&h=427" alt="">
<p>请同学们完善以下数据:</p>
<img src="img/三峡.png" alt="">
<span>基本信息</span>
<a href="https://www.baidu.com">百度</a>
<br>
<br>
姓名:<input type="text" value="张三">
密码:<input type="password" name="" id="">
<br><br>
性别:
<input type="radio" name="gender" id="g1"><label for="g1">男</label>
<input type="radio" name="gender" id="g2"><label for="g2">女</label>
<br><br>
兴趣:
<input type="checkbox">篮球
<input type="checkbox">乒乓球
<input type="checkbox">爬山
<input type="checkbox">玩儿游戏
<input type="checkbox">看动漫
<br><br>
籍贯:
<select name="" id="">
<option value="北京">北京</option>
<option value="成都">成都</option>
<option value="重庆">重庆</option>
<option value="上海">上海</option>
</select>
</body>
</html>
5.css选择器
css负责网页内容样式(让网页可以变得更好看)
css语法:
选择器(属性1:属性值1;属性2:属性值2…)
选择器:选中需要添加样式的标签
2.css选择器
独立存在的选择器有三个
1)元素选择器(标签选择器) - 将标签名作为选择器,选中所有指定的标签
p{} - 选中所有的p标签
2)id选择器 - 在id属性值前面加#号作为一个选择器,选中id属性值为指定值的标签
每一个可见的标签都可以设置id属性,并且一个页面中,同一个id值只有一个标签。
#id值{}
#p1 - 选中id属性值为p1的标签
3)class选择器 - 在class属性值前加.作为一个选择器,选中class属性值为指定值的标签
不同的标签可以有相同的class值,同一个标签可以有不同的class值(在class值后面空格加上class值,可以有多个class值)
.class值{}
.c1 - 获取class值为c1的所有标签
p.c1 - 获取class值为c1的p标签
.c1.c2 - 获取class值同时为c1和c2的标签
4)群组选择器 - 将多个选择器用逗号隔开作为一个选择器
p,a{} - 选中所有的p标签和所有的a标签
#p1,.c1,p{} - 所有id为p1的标签和class值为c1的标签以及所有的p标签
5)子代选择器 - 多个选择器用>号隔开作为一个选择器(只能有儿子)
div>p{} - 9
6)后代选择器 - 多个选择器用空格隔开作为一个选择器(儿子孙子都可以)
div p{}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- style标签中可以写css代码 -->
</head>
<body>
<!-- ------------1. 元素选择器案例 -------- -->
<style>
p{
color: red;
font-size: 30px;
}
</style>
<p>我是段落1</p>
<a href="">我是超链接1</a>
<div>我是div1</div>
<a href="">我是超链接2</a>
<p>我是段落2</p>
<!-- ------------2. id选择器案例 -------- -->
<style>
#p2{
color: green;
background-color: yellow;
}
</style>
<p>我是段落1</p>
<a href="">我是超链接1</a>
<div>我是div1</div>
<a href="">我是超链接2</a>
<p id="p2">我是段落2</p> -->
<!-- ------------3. class选择器案例 -------- -->
<!-- <style>
.c1{
color: red;
font-size: 30px;
}
.c2{
background-color: yellow;
}
p.c1{
text-decoration: line-through;
}
.c1.c2{
border: 1px solid blue;
}
</style>
<p class="c1 c2">我是段落1</p>
<a class="c2" href="">我是超链接1</a>
<div>我是div1</div>
<a class="c1" href="">我是超链接2</a>
<p id="p2">我是段落2</p>
<p class="c1">我是段落3</p>
<!-- ------------4. 群组选择器案例 -------- -->
<style>
a,p{
color: red;
font-size: 30px;
}
.c1,a{
background-color: yellow;
}
</style>
<p class="c1">我是段落1</p>
<a href="">我是超链接1</a>
<div>我是div1</div>
<a href="">我是超链接2</a>
<p>我是段落2</p>
<style>
p{
color: red;
}
div>p{
font-size: 30px;
}
div p{
background-color: yellow;
}
#box1>div p{
}
</style>
<p>我是段落1</p>
<div>
<p>我是段落2</p>
<span>
<p>我是段落5</p>
</span>
</div>
<div id="box1">
<p>我是段落3</p>
<div>
<span>
<div>
<p>我是段落4</p>
</div>
</span>
</div>
</div>
</body>
</html>
1.2 正则解析贝壳租房
import requests
from re import findall,finditer
import csv
# 1.获取网页数据
response = requests.get('https://cd.zu.ke.com/zufang')
result = response.text
# print(result)
# 2.解析数据
names = findall(r'(?s)<a class="twoline" .+?>(.+?)</a>',result)
names = [x.strip() for x in names]
prices = findall(r'<span class="content__list--item-price"><em>(\d+)</em>',result)
house =map(lambda l1,l2:(l1,l2),names,prices)
f = open('files/租房.csv','w',encoding='utf-8',newline='')
writer = csv.writer(f)
writer.writerow(['名称','价格'])
writer.writerows(list(house))
f.close()
1.3 图片下载
import requests
def download_image(url:str):
# 1.对图片地址发送请求
response = requests.get(url)
# 2.获取图片数据
data = response.content
# 3.将数据写入图片文件中
with open('files/宝儿姐.jpeg','wb') as f:
f.write(data)
if __name__ == '__main__':
download_image('https://img2.baidu.com/it/u=2655356050,2597134224&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=707')
1.4 图片批量下载(正则)
import requests
from re import findall
from uuid import uuid1 #可以创建唯一的id值
# 1.获取整个页面的数据
response = requests.get('https://cd.zu.ke.com/zufang')
content = response.text
# print(content)
# 2.解析数据获取所有房屋的图片地址
all_images = findall(r'(?s)<a\s+class="content__list--item--aside".+?>\s+<img.+?data-src="(.+?)"',content)
# print(all_images)
# 3.下载所有图片
def download_image(url:str):
# 1.对图片地址发送请求
response = requests.get(url)
# 2.获取图片数据
data = response.content
# 3.将数据写入图片文件中
with open(f'files/{uuid1()}.jpg','wb') as f:
f.write(data)
if __name__ == '__main__':
for i in all_images:
download_image(i)
1.5 浏览器伪装
import requests
headers = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
response = requests.get('',headers=headers)
print(response.text)
1.6 bs4解析
- bs4的作用
专门用来解析网页数据的第三方库。(基于css选择器解析网页数据)
这个库下载的时候用’beautifulsoup4’, 使用的时候用’bs4’
注意:在使用bs4做数据解析的时候,需要依赖’lxml’这个第三方库
导入解析相关类
from bs4 import BeautifulSoup
- bs4的用法
1)准备需要解析的数据(获取网页数据)
html = open('files/test.html', encoding='utf-8').read()
2)基于网页源代码创建BeautifulSoup对象
soup对象代表网页对应的html标签(代表整个网页)
soup = BeautifulSoup(html, 'lxml')
3)获取标签
soup.select(css选择器) - 在整个网页中获取css选择器选中的所有标签,返回值是一个列表,列表中元素是标签对象
soup.select_one(css选择器) - 在整个网页中获取css选择器选中的第一个标签,返回值是标签对象
result = soup.select('#box1 p')
print(result) # [<p>肖生克的救赎</p>, <p>霸王别姬</p>, <p>阿甘正传</p>]
result = soup.select_one('#box1 p')
print(result) # <p>肖生克的救赎</p>
标签对象.select(css选择器) - 在指定标签中获取css选择器选中的所有表情,返回值是一个列表,列表中元素是标签对象
标签对象.select_one(css选择器) - 在指定标签中获取css选择器选中的第一个标签,返回值是标签对象
result = soup.select('p')
print(result) # [<p>肖生克的救赎</p>, <p>霸王别姬</p>, <p>阿甘正传</p>, <p>我是段落1</p>]
box2 = soup.select_one('#box2')
result = box2.select('p')
print(result) # [<p>我是段落1</p>]
4)获取标签内容和标签属性
p = soup.select_one('p') # <p>肖生克的救赎</p>
img = soup.select_one('img')
a. 获取标签内容: 标签对象.text
print(p.text) # '肖生克的救赎'
b.获取标签属性值: 标签对象.attrs[属性名]
print(img.attrs['src'], img.attrs['alt'])
1.7 bs4解析豆瓣单页数据
import requests
from bs4 import BeautifulSoup
import csv
# 1.获取网页数据
def get_net_data(url:str):
headers = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
response = requests.get(url,headers=headers)
return response.text
# 2.网页数据解析
def analysis_data(html:str):
soup = BeautifulSoup(html,'lxml')
content = soup.select('.grid_view .info')
list2=[]
for i in content:
name = i.select_one('.title').text
info = i.select_one('.bd p').text.strip().split('\n')[-1].strip()
year,contry,plot=info.split('/')
grade = i.select_one('.rating_num').text
comment = i.select('.star span')[-1].text[:-3]
content1 = i.select_one('.inq').text
list2.append([name,grade,year.strip(),contry.strip(),plot.strip(),comment,content1])
with open('files/豆瓣第一页.csv','w',encoding='utf-8',newline='') as f:
writer = csv.writer(f)
writer.writerow(['名称','评分','年份','国家','类型','评论人数','剧情'])
writer.writerows(list2)
if __name__ == '__main__':
text1 = get_net_data('https://movie.douban.com/top250')
analysis_data(text1)
print('********************************华丽的分割线********************************')
# 1. 获取网页数据
def get_net_data(url: str):
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
response = requests.get(url, headers=headers)
return response.text
# 2. 网页数据解析
def analysis_data(html: str):
# 解析数据
soup = BeautifulSoup(html, 'lxml')
all_film_div = soup.select('.grid_view>li>.item')
all_data = []
for div in all_film_div:
name = div.select_one('.title').text
info = div.select_one('.bd>p').text.strip().split('\n')[-1].strip()
time, country, category = info.split('/')
score = div.select_one('.rating_num').text
comment_count = div.select('.star>span')[-1].text[:-3]
intro = div.select_one('.inq').text
all_data.append([name, score, time.strip(), country.strip(), category.strip(), comment_count, intro])
# 保存数据
f = open('files/第一页电影数据.csv', 'w', encoding='utf-8', newline='')
writer = csv.writer(f)
writer.writerow(['电影名', '评分', '上映时间', '国家', '类型', '评论数', '简介'])
writer.writerows(all_data)
if __name__ == '__main__':
result = get_net_data('https://movie.douban.com/top250')
analysis_data(result)
1.8解析豆瓣10页数据
import requests
from bs4 import BeautifulSoup
import csv
# 1.获取网页数据
def get_net_data(url:str):
headers = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
response = requests.get(url,headers=headers)
return response.text
# 2.网页数据解析
def analysis_data(html:str):
soup = BeautifulSoup(html,'lxml')
content = soup.select('.grid_view .info')
list2=[]
for i in content:
name = i.select_one('.title').text
info = i.select_one('.bd p').text.strip().split('\n')[-1].strip()
info_list=info.split('/')
year=info_list[0]
contry=info_list[-2]
plot=info_list[-1]
# print(year,contry,plot)
grade = i.select_one('.rating_num').text
comment = i.select('.star span')[-1].text[:-3]
content1 = i.select_one('.inq')
if content1:
intro=content1.text
else:
intro=''
list2.append([name,grade,year.strip(),contry.strip(),plot.strip(),comment,intro])
writer.writerows(list2)
def web():
with open('files/豆瓣电影.csv','a',encoding='utf-8',newline='') as f:
writer = csv.writer(f)
writer.writerow(['名称','评分','年份','国家','类型','评论人数','剧情'])
for i in range(0, 226, 25):
text1 = get_net_data(f'https://movie.douban.com/top250?start={i}&filter=')
analysis_data(text1)
if __name__ == '__main__':
web()
# 1. 获取网页数据
def get_net_data(url: str):
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
response = requests.get(url, headers=headers)
return response.text
# 2. 网页数据解析
def analysis_data(html: str):
# 解析数据
soup = BeautifulSoup(html, 'lxml')
all_film_div = soup.select('.grid_view>li>.item')
all_data = []
for div in all_film_div:
name = div.select_one('.title').text
info = div.select_one('.bd>p').text.strip().split('\n')[-1].strip()
# time, country, category = info.split('/')
info_list = info.split('/')
time = info_list[0]
country = info_list[-2]
category = info_list[-1]
score = div.select_one('.rating_num').text
comment_count = div.select('.star>span')[-1].text[:-3]
intro_span = div.select_one('.inq')
if intro_span:
intro = intro_span.text
else:
intro = ''
all_data.append([name, score, time.strip(), country.strip(), category.strip(), comment_count, intro])
writer.writerows(all_data)
print('保存成功!')
if __name__ == '__main__':
f = open('files/豆瓣电影.csv', 'w', encoding='utf-8', newline='')
writer = csv.writer(f)
writer.writerow(['电影名', '评分', '上映时间', '国家', '类型', '评论数', '简介'])
for page in range(0, 251, 25):
url = f'https://movie.douban.com/top250?start={page}&filter='
result = get_net_data(url)
analysis_data(result)