@[TOC](Requests+Etree+BeautifulSoup+Pandas+Path应用 | 获取页面指定区域数据存入html、excel文档)
1 需求来源
- 获取网页指定区域数据,并进行保存;
- 简略说便是pa chong的需求了。
2 需求细节
留意:请文明上网,本文仅作为学习用。叙述的是思路和办法,所以对被测验网站关键数据进行躲藏。如有需求,可学习思路后自行找测验对象进行学习。
- 某网站,进入后如下,有许多数据分类:
-
进入某个分类后有许多小分类,如电阻器中的页面:
-
而每个小类又有许多数据,那咱们便是要把这些数据下载下来进行保存:
3 规划剖析
根据以上【需求细节】,咱们现已大约明白需求做啥,便是要下载一个大的分类下的小类中的内容:
- 要恳求对应页面数据,那咱们需求用到的
requests.get
办法; - 恳求完数据后,要获取对应元素的html,要用到
etree.HTML
和tree.xpath
办法; - 因为这些大类或小类,其实本质上都是不同的链接,从页面看咱们可能需求获取
a
标签,那么需求运用BeautifulSoup
进行页面解析; - 下载下来的数据,咱们要进行保存到
html
格局的文件中,那咱们要用到根本的数据写入,比方open
和write
办法; - 想把下载下来的
html
原格局保存到excel中,那需求对html
和excel
格局进行解析,需求运用pandas
进行处理; - 这个中心进程中,需求对文件和途径进行处理,所以还需求用到
Path
办法; - 终究咱们把脚本打包成exe便利运行和运用,那需求用到打包东西
Pyinstaller
处理。
4 技术栈
- 从【3 规划剖析】来看,咱们需求用到以下东西环境。
东西 | 版本 | 用途 |
---|---|---|
Python |
V3.7.0 | 脚本规划 |
beautifulsoup4 |
V4.11.1 | html页面数据解析 |
lxml |
V4.6.3 |
etree.HTML 、tree.xpath 获取对应元素的html |
pandas |
V1.1.5 | excel数据处理 |
requests |
V2.24.0 | 页面数据恳求 |
- 仿制以下内容命名为
requirements.txt
,直接运用pip install -r requirements.txt
即可安装需求的包;
beautifulsoup4==4.11.1
lxml==4.6.3
pandas==1.1.5
requests==2.24.0
5 规划实现
- 先引入一切需求的包:
import requests
from lxml import etree
from bs4 import BeautifulSoup
import pandas
import os
import time
from pathlib import Path
- 创立基类Tools:
class Tools(object):
"""公共办法(东西)作为基类被后续调用"""
5.1 封装公共办法类Tools
5.1.1 封装数据恳求办法get_category
- 创立办法get_category,传入四个参数:
def get_category(self,
curt_url,
curt_xpath,
curt_list,
curt_headers):
"""
恳求办法封装
:param curt_url: 恳求地址
:param curt_xpath: 对应table xpath
:param curt_list: 寄存列表
:param curt_headers: 恳求头
:return: 无回来
"""
- 为什么要这么做?为了防止代码冗余,后续有许多地方用到数据恳求和获取,所以进行了封装。而传入的四个参数,根本是变化的,所以用到时分,传入需求的参数即可;
- 在每次恳求前加个延迟:
time.sleep(1)
,防止恳求太过频频; - 运用
requests.get
办法,获取方针地址数据,其间要参加两个参数,主要防止恳求报SSl过错:
res = requests.get(curt_url,
verify=False,
headers=curt_headers)
- 运用
etree.HTML
办法回来的数据进行html转化:
tree = etree.HTML(res.content)
- 运用
tree.xpath
办法获取该页面中指定元素的内容:
div = tree.xpath(curt_xpath)
- 运用以下办法进行格局转化,获取的数据是byte字节,转化成str类型;
div_str = etree.tostring(div[0])
div_str1 = str(div_str, "UTF-8")
- 运用
BeautifulSoup
办法解析页面html,获取a
标签的一切链接内容,便是大类或小类的名字对应的链接了;
soup = BeautifulSoup(div_str1)
for k in soup.find_all('a'):
curt_list.append(k['href'])
-
get_category
办法源码:
def get_category(self,
curt_url,
curt_xpath,
curt_list,
curt_headers):
"""
恳求办法封装
:param curt_url: 恳求地址
:param curt_xpath: 对应table xpath
:param curt_list: 寄存列表
:param curt_headers: 恳求头
:return: 无回来
"""
time.sleep(1)
res = requests.get(curt_url,
verify=False,
headers=curt_headers) # 接口数据恳求办法
tree = etree.HTML(res.content) # 获取回来数据的内容
div = tree.xpath(curt_xpath) # 获取当时页面需求的table xpath对应的内容
div_str = etree.tostring(div[0]) # 格局转化
div_str1 = str(div_str, "UTF-8") # byte转为str
# print(div_str1)
soup = BeautifulSoup(div_str1) # BeautifulSoup解析页面html
for k in soup.find_all('a'): # 获取a标签
curt_list.append(k['href'])
5.1.2 封装html数据写入办法write_html
- 便是把以上获取的内容存入html格局的文件中;
- 这个简略,直接上代码:
def write_html(self, file, txt):
"""
公共办法:把获取的数据写入文本内容到文件【html格局】
:param file: 文件名
:param txt: 文本内容
:return: 回来成功或失利
"""
try:
with open(file, 'w', encoding='utf-8') as f:
f.write(txt)
time.sleep(3)
f.close()
return f"{file}写入: 成功"
except:
return f"{file}写入: 失利"
5.1.3 封装html转excel办法html_to_excel
- 简略说,便是把html文件转化成excel格局;
- 传入五个参数:
def html_to_excel(self,
base_dir,
big_dir,
small_dir,
full_path,
new_file_path):
"""
将html文件转化成excel格局的文件
:param base_dir: 文件寄存基地址,默认脚本的上一层目录
:param big_dir: 大类目录
:param small_dir: 小类目录
:param excel_dir: 寄存excel目录
:param sheet_n: 寄存sheet的称号=小类
:param full_path: 一切sheet兼并目录
:param new_file_path: 终究兼并的某个小类的excel
:return:无回来
"""
- 大约思路是:
①翻开指定目录下的html格局文件; ②循环遍历一切的html格局文件,运用pandas.read_html进行数据读取; ③运用pandas.ExcelWriter办法写入excel; ④写入excel后是每个html寄存在每个sheet中; ⑤兼并一切的sheet为一个excel。
- 直接上代码:
def html_to_excel(self,
base_dir,
big_dir,
small_dir,
full_path,
new_file_path):
"""
将html文件转化成excel格局的文件
:param base_dir: 文件寄存基地址,默认脚本的上一层目录
:param big_dir: 大类目录
:param small_dir: 小类目录
:param excel_dir: 寄存excel目录
:param sheet_n: 寄存sheet的称号=小类
:param full_path: 一切sheet兼并目录
:param new_file_path: 终究兼并的某个小类的excel
:return:无回来
"""
excel_dir = base_dir + "\\" + big_dir + "\\" + small_dir + "\\"
sheet_n = small_dir
# sheet_n = "1-陶瓷电容器"
os.chdir(excel_dir)
for filename in os.listdir(excel_dir):
print(filename)
try:
with open(excel_dir + filename, 'rb') as f:
df = pandas.read_html(f.read(), header=1, encoding='utf-8')
bb = pandas.ExcelWriter(excel_dir + filename + ".xlsx")
df[0].to_excel(bb, index=False)
bb.close()
except Exception as e:
print("反常:" + e)
time.sleep(3)
workbook = pandas.ExcelWriter(full_path)
folder_path = Path(excel_dir)
file_list = folder_path.glob('*.xlsx*')
for i in file_list:
stem_name = i.stem
data = pandas.read_excel(i, sheet_name=0)
data.to_excel(workbook, sheet_name=stem_name, index=False)
time.sleep(2)
workbook.save()
workbook.close()
time.sleep(2)
data2 = pandas.read_excel(full_path, sheet_name=None)
data3 = pandas.concat(data2, ignore_index=True)
# new_file_path = "兼并.xlsx"
data3.to_excel(new_file_path, sheet_name=sheet_n, index=False)
5.2 两个全局变量寄存获取的数据称号
category_list = [] # 寄存一切大类
category_list_small = [] # 寄存一切小类
5.3 创立数据处理和获取类DataBase
5.3.1 初始化类
def __init__(self):
# self.tools = Tools()
self.url = 'xxxx' # 方针网站
self.headers = {'Connection': 'close'} # 恳求头,防止ssl报错
# self.big_num = 3 # 第几个大类,从0开端
# self.small_num = 0 # 第几个小类,从0开端
self.net_xpath = '/html/body/div[5]/div/div[2]' # 网站一切大类的table xpath
self.xpath_big = ['/html/body/div[3]/div[2]'] # 对应大类中的小类的table xpath
self.xpath_small = ['/html/body/div[4]/div'] # 对应小类的内容table xpath
5.3.2 获取一切大类称号存入列表
def get_big_category(self):
"""获取网站中一切的类别,寄存列表中"""
self.get_category(self.url,
self.net_xpath,
category_list,
self.headers)
print(f"1========={category_list}")
5.3.3 获取一切大类中小类的称号存入列表
def get_small_category(self, big_num):
"""获取某个大类中小类一切的类别,寄存列表中"""
self.get_category(f'{self.url}{category_list[big_num]}',
self.xpath_big[0],
category_list_small,
self.headers)
print(f"获取的大类是: {category_list[big_num]} ,如下:")
5.3.4 获取小类中页面的内容
def get_small_content(self, i, small_num):
"""获取小类中一切内容"""
print(f"获取的大类对应的小类是:{category_list_small[small_num]}")
time.sleep(1)
url_1 = f'{self.url}{category_list_small[small_num]}?page={i}'
print(f"恳求的小类的域名为:{url_1}")
res = requests.get(url_1, verify=False, headers=self.headers)
tree = etree.HTML(res.content)
div = tree.xpath(self.xpath_small[0])
div_str = etree.tostring(div[0])
div_str1 = str(div_str, "UTF-8")
time.sleep(2)
return div_str1
5.4 办法调用main规划
5.4.1 输出输入规矩
def main():
print("*" * 20)
print("在运行前请所了解下规矩:\n"
"1、依照网页显示,大类称号输入 数字-大类称号,如1-电阻器\n"
"2、小类称号输入 数字-小类称号,如1-固定电阻器\n"
"3、巨细类前边的数字表明第几个\n"
"4、假如输错不做判别,仅仅寄存的途径需求自己查找,建议一次性输入正确\n"
"5、!!!!!程序履行进程请勿封闭任何窗口!!!!!")
print("*" * 20)
5.4.2 对当时脚本途径进行处理
base_file = os.path.dirname(os.path.abspath("test_database_final.py"))
print("#" * 20)
print("程序将开端履行,请稍后......\n"
"程序现已发动~\n"
f"程序发动目录为:{base_file}\n"
"初始化数据......")
print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n"
"1-电阻器 2-连接器 3-连接器支架 4-电容器 5-振荡器 \n"
"6-晶体/谐振器 7-电源电路 8-开关 9-传感器/温度传感器 10-光电 \n"
"11-光纤 12-二极管 13-电路维护 14-存储 15-信号电路 \n"
"16-电感器 17-端子 18-插座 19-微控制器和处理器 20-射频和微波 \n"
"21-逻辑 22-晶体管 23-继电器 24-转化器 25-过滤器 \n"
"26-触发设备 27-RC网络 28-可编程逻辑 29-电信电路 30-驱动程序和接口 \n"
"31-放大器电路 32-耐热支撑设备 33-变压器 34-消费电路 35-电池 \n"
"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
5.4.3 从键盘输入要获取的数据信息
big = input("请输入大类的称号(如1-电阻器): ")
small = input("请输入小类的称号(如1-固定电阻器): ")
num = int(input("请输入小类的页数(如50,需求从网站检查): "))
b_n = int(input("请输入该大类对应的序号,共35个大类,从左到右数从0开端,比方0: "))
m_n = int(input("请输入该小类对应的序号,从0开端,比方0: "))
print(f"通过输入,咱们要获取的数据为:第{b_n + 1}个大类中的第{m_n + 1}个小类\n"
f"即:{big}中的{small}")
5.4.4 数据调用
data_base = DataBase()
data_base.get_big_category()
data_base.get_small_category(b_n)
5.4.5 循环换入每页中的数据
for i in range(1, num+1):
get_content = data_base.get_small_content(i, m_n)
print(f"第{i}次获取:获取的数据开端写入文件,文件名为:第{i}页.html")
file = f"{base_file}\\{big}\\{small}"
if os.path.exists(file) is False:
os.makedirs(file)
data_base.write_html(file=f"{file}\\第{i}页.html",
txt=get_content)
time.sleep(1)
5.4.6 获取的数据兼并存入终究的excel
data_base.html_to_excel(base_file,
big,
small,
f"{small}sheet.xlsx",
f"{small}.xlsx")
5.4.7 main办法源码
def main():
print("*" * 20)
print("在运行前请所了解下规矩:\n"
"1、依照网页显示,大类称号输入 数字-大类称号,如1-电阻器\n"
"2、小类称号输入 数字-小类称号,如1-固定电阻器\n"
"3、巨细类前边的数字表明第几个\n"
"4、假如输错不做判别,仅仅寄存的途径需求自己查找,建议一次性输入正确\n"
"5、!!!!!程序履行进程请勿封闭任何窗口!!!!!")
print("*" * 20)
base_file = os.path.dirname(os.path.abspath("test_database_final.py"))
print("#" * 20)
print("程序将开端履行,请稍后......\n"
"程序现已发动~\n"
f"程序发动目录为:{base_file}\n"
"初始化数据......")
print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n"
"1-电阻器 2-连接器 3-连接器支架 4-电容器 5-振荡器 \n"
"6-晶体/谐振器 7-电源电路 8-开关 9-传感器/温度传感器 10-光电 \n"
"11-光纤 12-二极管 13-电路维护 14-存储 15-信号电路 \n"
"16-电感器 17-端子 18-插座 19-微控制器和处理器 20-射频和微波 \n"
"21-逻辑 22-晶体管 23-继电器 24-转化器 25-过滤器 \n"
"26-触发设备 27-RC网络 28-可编程逻辑 29-电信电路 30-驱动程序和接口 \n"
"31-放大器电路 32-耐热支撑设备 33-变压器 34-消费电路 35-电池 \n"
"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
big = input("请输入大类的称号(如1-电阻器): ")
small = input("请输入小类的称号(如1-固定电阻器): ")
num = int(input("请输入小类的页数(如50,需求从网站检查): "))
b_n = int(input("请输入该大类对应的序号,共35个大类,从左到右数从0开端,比方0: "))
m_n = int(input("请输入该小类对应的序号,从0开端,比方0: "))
print(f"通过输入,咱们要获取的数据为:第{b_n + 1}个大类中的第{m_n + 1}个小类\n"
f"即:{big}中的{small}")
data_base = DataBase()
data_base.get_big_category()
data_base.get_small_category(b_n)
for i in range(1, num+1):
get_content = data_base.get_small_content(i, m_n)
print(f"第{i}次获取:获取的数据开端写入文件,文件名为:第{i}页.html")
file = f"{base_file}\\{big}\\{small}"
if os.path.exists(file) is False:
os.makedirs(file)
data_base.write_html(file=f"{file}\\第{i}页.html",
txt=get_content)
time.sleep(1)
data_base.html_to_excel(base_file,
big,
small,
f"{small}sheet.xlsx",
f"{small}.xlsx")
5.5 主程序调用
if __name__ == "__main__":
main()
input('Press Enter to exit…')
6 完好源码
# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/10/11
# 文件称号:test_database_final.py
# 作用:xxx
# 博客:https://blog.csdn.net/NoamaNelson
import requests
from lxml import etree
from bs4 import BeautifulSoup
import pandas
import os
import time
from pathlib import Path
class Tools(object):
"""公共办法(东西)作为基类被后续调用"""
def get_category(self,
curt_url,
curt_xpath,
curt_list,
curt_headers):
"""
恳求办法封装
:param curt_url: 恳求地址
:param curt_xpath: 对应table xpath
:param curt_list: 寄存列表
:param curt_headers: 恳求头
:return: 无回来
"""
time.sleep(1)
res = requests.get(curt_url,
verify=False,
headers=curt_headers) # 接口数据恳求办法
tree = etree.HTML(res.content) # 获取回来数据的内容
div = tree.xpath(curt_xpath) # 获取当时页面需求的table xpath对应的内容
div_str = etree.tostring(div[0]) # 格局转化
div_str1 = str(div_str, "UTF-8") # byte转为str
# print(div_str1)
soup = BeautifulSoup(div_str1) # BeautifulSoup解析页面html
for k in soup.find_all('a'): # 获取a标签
curt_list.append(k['href']) # 循环获取href链接
def write_html(self, file, txt):
"""
公共办法:把获取的数据写入文本内容到文件【html格局】
:param file: 文件名
:param txt: 文本内容
:return: 回来成功或失利
"""
try:
with open(file, 'w', encoding='utf-8') as f:
f.write(txt)
time.sleep(3)
f.close()
return f"{file}写入: 成功"
except:
return f"{file}写入: 失利"
def html_to_excel(self,
base_dir,
big_dir,
small_dir,
full_path,
new_file_path):
"""
将html文件转化成excel格局的文件
:param base_dir: 文件寄存基地址,默认脚本的上一层目录
:param big_dir: 大类目录
:param small_dir: 小类目录
:param excel_dir: 寄存excel目录
:param sheet_n: 寄存sheet的称号=小类
:param full_path: 一切sheet兼并目录
:param new_file_path: 终究兼并的某个小类的excel
:return:无回来
"""
excel_dir = base_dir + "\\" + big_dir + "\\" + small_dir + "\\"
sheet_n = small_dir
# sheet_n = "1-陶瓷电容器"
os.chdir(excel_dir)
for filename in os.listdir(excel_dir):
print(filename)
try:
with open(excel_dir + filename, 'rb') as f:
df = pandas.read_html(f.read(), header=1, encoding='utf-8')
bb = pandas.ExcelWriter(excel_dir + filename + ".xlsx")
df[0].to_excel(bb, index=False)
bb.close()
except Exception as e:
print("反常:" + e)
time.sleep(3)
workbook = pandas.ExcelWriter(full_path)
folder_path = Path(excel_dir)
file_list = folder_path.glob('*.xlsx*')
for i in file_list:
stem_name = i.stem
data = pandas.read_excel(i, sheet_name=0)
data.to_excel(workbook, sheet_name=stem_name, index=False)
time.sleep(2)
workbook.save()
workbook.close()
time.sleep(2)
data2 = pandas.read_excel(full_path, sheet_name=None)
data3 = pandas.concat(data2, ignore_index=True)
# new_file_path = "兼并.xlsx"
data3.to_excel(new_file_path, sheet_name=sheet_n, index=False)
category_list = [] # 寄存一切大类
category_list_small = [] # 寄存一切小类
class DataBase(Tools):
def __init__(self):
# self.tools = Tools()
self.url = 'xxxxx' # 方针网站
self.headers = {'Connection': 'close'} # 恳求头,防止ssl报错
# self.big_num = 3 # 第几个大类,从0开端
# self.small_num = 0 # 第几个小类,从0开端
self.net_xpath = '/html/body/div[5]/div/div[2]' # 网站一切大类的table xpath
self.xpath_big = ['/html/body/div[3]/div[2]'] # 对应大类中的小类的table xpath
self.xpath_small = ['/html/body/div[4]/div'] # 对应小类的内容table xpath
def get_big_category(self):
"""获取网站中一切的类别,寄存列表中"""
self.get_category(self.url,
self.net_xpath,
category_list,
self.headers)
print(f"1========={category_list}")
def get_small_category(self, big_num):
"""获取某个大类中小类一切的类别,寄存列表中"""
self.get_category(f'{self.url}{category_list[big_num]}',
self.xpath_big[0],
category_list_small,
self.headers)
print(f"获取的大类是: {category_list[big_num]} ,如下:")
def get_small_content(self, i, small_num):
"""获取小类中一切内容"""
print(f"获取的大类对应的小类是:{category_list_small[small_num]}")
time.sleep(1)
url_1 = f'{self.url}{category_list_small[small_num]}?page={i}'
print(f"恳求的小类的域名为:{url_1}")
res = requests.get(url_1, verify=False, headers=self.headers)
tree = etree.HTML(res.content)
div = tree.xpath(self.xpath_small[0])
div_str = etree.tostring(div[0])
div_str1 = str(div_str, "UTF-8")
time.sleep(2)
return div_str1
def main():
print("*" * 20)
print("在运行前请所了解下规矩:\n"
"1、依照网页显示,大类称号输入 数字-大类称号,如1-电阻器\n"
"2、小类称号输入 数字-小类称号,如1-固定电阻器\n"
"3、巨细类前边的数字表明第几个\n"
"4、假如输错不做判别,仅仅寄存的途径需求自己查找,建议一次性输入正确\n"
"5、!!!!!程序履行进程请勿封闭任何窗口!!!!!")
print("*" * 20)
base_file = os.path.dirname(os.path.abspath("test_database_final.py"))
print("#" * 20)
print("程序将开端履行,请稍后......\n"
"程序现已发动~\n"
f"程序发动目录为:{base_file}\n"
"初始化数据......")
print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n"
"1-电阻器 2-连接器 3-连接器支架 4-电容器 5-振荡器 \n"
"6-晶体/谐振器 7-电源电路 8-开关 9-传感器/温度传感器 10-光电 \n"
"11-光纤 12-二极管 13-电路维护 14-存储 15-信号电路 \n"
"16-电感器 17-端子 18-插座 19-微控制器和处理器 20-射频和微波 \n"
"21-逻辑 22-晶体管 23-继电器 24-转化器 25-过滤器 \n"
"26-触发设备 27-RC网络 28-可编程逻辑 29-电信电路 30-驱动程序和接口 \n"
"31-放大器电路 32-耐热支撑设备 33-变压器 34-消费电路 35-电池 \n"
"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
big = input("请输入大类的称号(如1-电阻器): ")
small = input("请输入小类的称号(如1-固定电阻器): ")
num = int(input("请输入小类的页数(如50,需求从网站检查): "))
b_n = int(input("请输入该大类对应的序号,共35个大类,从左到右数从0开端,比方0: "))
m_n = int(input("请输入该小类对应的序号,从0开端,比方0: "))
print(f"通过输入,咱们要获取的数据为:第{b_n + 1}个大类中的第{m_n + 1}个小类\n"
f"即:{big}中的{small}")
data_base = DataBase()
data_base.get_big_category()
data_base.get_small_category(b_n)
for i in range(1, num+1):
get_content = data_base.get_small_content(i, m_n)
print(f"第{i}次获取:获取的数据开端写入文件,文件名为:第{i}页.html")
file = f"{base_file}\\{big}\\{small}"
if os.path.exists(file) is False:
os.makedirs(file)
data_base.write_html(file=f"{file}\\第{i}页.html",
txt=get_content)
time.sleep(1)
data_base.html_to_excel(base_file,
big,
small,
f"{small}sheet.xlsx",
f"{small}.xlsx")
if __name__ == "__main__":
main()
input('Press Enter to exit…')
7 Pyinstaller打包
- 直接运用以下命令打包:
pyinstaller -F test_database_final.py
- 打包后生成两个文件夹:
- 双击运行如下exe即可:
8 运行作用