@TOC
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 设计剖析】来看,咱们须要用到以下工具环境。工具版本用处PythonV3.7.0脚本设计beautifulsoup4V4.11.1html页面数据解析lxmlV4.6.3etree.HTML、tree.xpath获取对应元素的htmlpandasV1.1.5excel数据处理requestsV2.24.0页面数据申请复制以下内容命名为 requirements.txt,间接应用pip install -r requirements.txt 即可装置须要的包;beautifulsoup4==4.11.1lxml==4.6.3pandas==1.1.5requests==2.24.05 设计实现先引入所有须要的包:import requestsfrom lxml import etreefrom bs4 import BeautifulSoupimport pandasimport osimport timefrom pathlib import Path创立基类Tools:class Tools(object): """公共办法(工具)作为基类被后续调用"""5.1 封装公共办法类Tools5.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 创立数据处理和获取类DataBase5.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 xpath5.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_str15.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/NoamaNelsonimport requestsfrom lxml import etreefrom bs4 import BeautifulSoupimport pandasimport osimport timefrom pathlib import Pathclass 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_str1def 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打包后生成两个文件夹:
...