爬虫练习和bs4使用
爬虫阶段训练和bs4使用
- 菜场价格爬取
- 爬虫解析库bs4
- 红牛分公司爬取
菜场价格爬取
思路
1.查看页面加载方式,右键网络源代码 2.获取数据不在存在,此网站为js动态请求 3.在network中XHR,查找信息获取URL,确定请求方法 4.获取数据结果,选择需要的数据,发现list是我们需要的数据 5.分析数据,发现ID用于确定具体信息数据,一个组对应一个蔬菜 结论: 循环获取信息,发送post请求,就可以循环获取每个蔬菜的详情信息 6.查找目录数据信息与页数对应关系。 9.current参数用于控制页数,可通过for循环获取页数,循环输出个页面的数据 10.查看页面数为181417页设置循环,可以设置循环页数,以免服务器和电脑过载
'''
爬取数据时,最好设置一个时间间隔,避免服务器工作量增大,客服端IP被封
'''
代码
# 调用模块 import requests import json import os # 判断是否存在蔬菜文件夹 if not os.path.exists(r'蔬菜'): # 创建蔬菜文件 os.mkdir(r'蔬菜') # 设置循环值,即页数 vert_page=int(input('请输入开始页码:')) # 结束页码 end_page=int(input('请输入结束页码:')) # 判断页码是否符合逻辑 if vert_page >= end_page: # 提示信息 print('结束页码不能小于开始页码') # 符合逻辑 else: # 设置循环 while vert_page <= end_page: # 发送post请求 res=requests.post("http://www.xinfadi.com.cn/getPriceData.html", # 请求头 headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36"}, # 请求体 data={"limit": 20, # 页码参数 "current": vert_page, "pubDateStartTime":"", "pubDateEndTime":"", "prodPcatid":"", "prodCatid":"", "prodName":""} ) # 获取一页整体的蔬菜信息 blist=res.json().get("list") # 循环获取每个信息 for vert_id in blist: # 定义对应变量,蔬菜名 cname=vert_id.get('prodName') # 定义对应变量,生产地 cplace=vert_id.get('place') # 定义单位 cinfo=vert_id.get('unitfo') # cavPrice=vert_id.get('avgPrice') # 获取信息 print('菜名%s,产地%s,单位%s,品均价%s'%(cname,cplace,cinfo,cavPrice)) # 见蔬菜信息写入文件 with open(r'蔬菜\蔬菜%s.txt'%vert_id.get('prodName'), 'w',encoding="utf8") as f: # 以json格式,一行行写入 json.dump(vert_id,f) # 增加页码 vert_page+=1;
爬虫解析库bs4
bs4全名beautiful soup4
可以从HTML和XML文件中提取数据的Python库,他能够通过个人喜欢的转换器实现惯用的文档导航,查找,修改文档的方式,bs会省数小时甚至数天的工作时间
模块下载
方法1:
pycharm终端界面或dos界面,如果速度慢,可以加-i改变网络地址
pip3 install beautifulsoup4 -i
方法2:
点击file>>>settings>>>项目名>>>interperter>>>加号>>>输入模块名>>>install
配套解析器下载
bs4模块也调用了其他解析器,不下载就无法使用,下载方式和上述模块相同
pip3 install lxml
bs4模块基本使用
调用模块
from bs4 import BeautifulSoup
实验前准备
html_doc = """ <html> <head> <title>The Dormouse's story</title> </head> <body> <p class="title"> <b>The Dormouse's story</b> </p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a> <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a> and they lived at the bottom of a well.</p> <p class="story">...</p> </body> </html> """
构造解析对象
语法:
语法: soup =BeautifulSoup(目的变量名, '文件格式') eg: soup = BeautifulSoup(html_doc, 'lxml')
bs4内置方法
输出从上往下第一个a标签
# soup.标签名 print(soup.a)
获取内部标签,包含内部所有的后代标签文本
print(soup.p.text)
print(soup.a.text)
获取标签内部所有的属性 字典数据类型
print(soup.p.attrs) print(soup.a.attrs)
获取标签内部相应的属性的value值
print(soup.p.attrs.get('fog')) print(soup.a.attrs.get('href'))
简写省略attrs参数
print(soup.a.get('href'))
获取标签内部所有的子标签
语法: soup.标签名.children eg:
# 需要循环取值才可以拿到 for i in soup.p.children: print(i)
获取标签内部所有的子标签
语法: soup.标签名.contents eg: print(soup.p.contents)
获取标签所有的父标签
语法: soup.标签名.parent eg: print(soup.p.parent)
获取标签所有的父标签(迭代器)
语法: soup.标签名.parents eg: # 返回为迭代器 for i in soup.p.parents: print(i)
核心操作
1.find方法
缺点:只能找到符合条件的第一个,返回结果是一个标签对象
语法: soup.find(name='标签名',attrs={'属性':'属性名'}) eg: # 查找a标签 默认只找符合条件的第一个 print(soup.find(name='a'))
# 找id为link2的a标签 默认只找符合条件的第一个 print(soup.find(name='a',id='link2'))
# 为了解决关键字冲突 会加下划线 print(soup.find(name='p',class_='title'))
# 使用attrs参数,可以避免关键字冲突 print(soup.find(name='a', attrs={'id': 'link3','class':'sister'}))
# 没有name参数,也可以查找符合后续条件的标签
print(soup.find(attrs={'id': 'link3','class':'sister'}))
2.find_all方法
优点:查找所有符合条件的标签 ,返回结果是一个列表
语法: name参数可省略,find_all方法与find一致 soup.findall('标签名') eg:
# 查找所有a标签 print(soup.find_all('a'))
# 查找所有clas为sister的 print(soup.find_all(attrs={'class':'sister'}))
3.select方法
需要使用CSS选择器,返回一个列表
标签选择器
语法: soup.select() ''' 1.标签选择器:直接书写标签名即可 2.id选择器:#d1 相当于写了 id='d1' 3.class选择器:.c1 相当于写了 class=c1 4.儿子选择器(大于号):选择器可以混合使用 div>p 查找div标签内部所有的儿子p 5.后代选择器(空格):选择器可以混合使用 div p 查找div标签内部所有的后代p
eg:
# 查找class含有title的标签 print(soup.select('.title'))
# 查看class含有sister标签内部所有的后代span print(soup.select('.sister span'))
# 查找id等于link1的标签 print(soup.select('#link1'))
# 查找id等于link1标签内部所有的后代span print(soup.select('#link1 span'))
# 查找class等于story标签内部所有id为link的标签 print(soup.select('.story #link1'))
#也可以嵌套select,但其实没必要,一条select就可以了 print(soup.select('.story')[0].select('#link1'))
爬取红牛分公司数据
要求:获取红牛所有分公司详细数据(名称 地址 邮箱 电话)
思路:
1.判断数据加载方式,打开网络源地址,查找数据,发现为直接加载
2.进入network,查找url地址、请求方式或请求头等信息
3.执行代码筛选
代码
# 调用模块 import requests from bs4 import BeautifulSoup # 请求数据 res=requests.get('http://www.redbull.com.cn/about/branch') # 构造解析对象 soup =BeautifulSoup(res.text,'lxml') # 获取公司名 h2_list=soup.find_all('h2') # 生成公司名列表 namelist=[title.text for title in h2_list] # 获取具体地址 p_add=soup.find_all(attrs={'class':'mapIco'}) # 生成地址列表 addr_list = [tag.text for tag in p_add] # 获取邮箱 p_mail=soup.select('.mailIco') # 生成邮箱列表 email_list = [tag.text for tag in p_mail] # 获取电话 p_phone=soup.select('.telIco') # # 生成电话列表 phone_list = [tag.text for tag in p_phone] # 循环输出数,以表长为索引值 for i in range(len(h2_list)): print(''' 公司名称:%s 公司地址:%s 公司邮箱:%s 公司电话:%s '''%(addr_list[i],addr_list[i], email_list[i], phone_list[i]))