核心方法:价值500元的Python爬虫+pyqt5小案例

优采云 发布时间: 2022-10-27 00:14

  核心方法:价值500元的Python爬虫+pyqt5小案例

  Python实战:request+pyqt5小案例

  一、*敏*感*词*目的简要说明

  本案例的需求主要分为两部分,一部分是爬虫,另一部分封装成小程序,下面会详细介绍。

  1.1 目标1:爬虫

  1.1.1 输入目标网址:

  1.1.2。如上图,输入编号进行搜索,如中药准字Z41021087

  1.1.3。进入如下网页,点击下图红框进入详情页面

  1.1.4。采集详情页下方红框内的11个项目按价格升序排列

  (1) 通用名称

  (2) 包装规格

  (三)生产企业

  (4) 批准文号

  (5) 最低价

  (6) 最低价库存

  (7) 次低价格

  (8) 次低价库存

  (9) 每次低价

  (10)二次低价库存

  (11) 零售商数量

  1.2 目标2:将爬虫封装成小程序

  要将爬虫功能封装成一个小程序,需要实现输入要排除的店铺名称,输入采集时要排除的最小库存数量的能力。

  软件采集 步骤

  第一步:点击开始:导入需要采集的审批单号信息表单,只搜索表单是否收录审批单号字段,其他字段忽略

  第二步:点击开始:软件开始自动运行,采集完成后会自动进入csv文件,并在软件中显示。

  软件风格如下

  2.案例代码实现2.1爬虫代码关键步骤:

  2.1.1 根据表格数据得到国标号后,需要根据检索到的对应药品的页数来判断页数。即根据下图中紫色部分的个数除以每页显示的数据量,就可以得到页数,进行翻页处理。

  2.1.2 进入每个药品详情页,需要按照价格升序排列,通过网页观察,如下图,只需将相关参数拼接到详情页的url即可。

  2.1.3 需要采集满足不包括店铺名称和最小数量的前三低价的数据:可以使用if语句判断店铺名称、数量,满足条件的数据条件形成一个小列表,然后将小列表追加到一个大列表中,判断大列表的长度是否大于等于3,大于等于跳出循环可以得到前三个低价的数据。

  2.2 小程序关键步骤

  基于pyqt5写的,不知道写什么,也是边学视频边写的。您可以自己阅读代码。业余玩家,代码难看,见谅!

  集成代码:

  测试表格:

  我只是打了几行数据,只要表格中收录国标号的栏目。

  下面的代码定义了3个类,分别是**(1)MainWindow:小程序的主体**,(2)InputQDialog:点击启动一个窗口供用户输入表单路径,(3)NewTaskTread:线程执行爬虫

  import sys

import os

import pandas as pd

import math

import requests

from lxml import etree

from fake_useragent import UserAgent

from PyQt5.QtCore import Qt

from PyQt5.QtCore import QThread, pyqtSignal

from PyQt5.QtWidgets import QApplication, QWidget

from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QPushButton, QLineEdit, QTableWidget, QTableWidgetItem, QLabel

from PyQt5.QtWidgets import QMessageBox, QDialog

BASE_DIR = os.path.dirname(os.path.realpath(sys.argv[0]))

# 小程序主题框架

class MainWindow(QWidget):

def __init__(self):

super().__init__()

self.init_ui()

# 初始化 包含init_header(功能区)及init_form(表格区),两个纵向排列的区域

def init_ui(self):

self.setWindowTitle('药房网采集系统')

self.resize(1450, 450)

self.terminate = False

layout = QVBoxLayout()

layout.addLayout(self.init_header())

layout.addLayout(self.init_form())

self.setLayout(layout)

self.show()

# 功能区(包括:排除店名,排除数量,开始,停止)

def init_header(self):

input_layout = QHBoxLayout()

label_exclude = QLabel("排除的店名:", self)

input_layout.addWidget(label_exclude)

self.input_exclude_name = input_exclude_name = QLineEdit()

input_layout.addWidget(input_exclude_name)

label_exclude = QLabel("最低库存:", self)

input_layout.addWidget(label_exclude)

self.input_exclude_court = input_exclude_court = QLineEdit()

input_layout.addWidget(input_exclude_court)

input_layout.addStretch()

btn_start = QPushButton('开始')

btn_start.clicked.connect(self.event_btn_start)

input_layout.addWidget(btn_start)

btn_end = QPushButton('停止')

btn_end.clicked.connect(self.event_btn_end)

input_layout.addWidget(btn_end)

input_layout.addStretch()

return input_layout

# 表格区,用于数据展示

def init_form(self):

form_layout = QHBoxLayout()

self.tab = tab = QTableWidget(0, 12)

table_header = [

{'field': 'id', 'text': '序号', 'width': 80},

{'field': 'name', 'text': '商品名称', 'width': 120},

{'field': 'company', 'text': '生产厂家', 'width': 200},

<p>

{&#39;field&#39;: &#39;spice&#39;, &#39;text&#39;: &#39;商品规格&#39;, &#39;width&#39;: 200},

{&#39;field&#39;: &#39;literacy&#39;, &#39;text&#39;: &#39;批准文号&#39;, &#39;width&#39;: 100},

{&#39;field&#39;: &#39;min_price&#39;, &#39;text&#39;: &#39;最低价&#39;, &#39;width&#39;: 100},

{&#39;field&#39;: &#39;min_price_num&#39;, &#39;text&#39;: &#39;盒数&#39;, &#39;width&#39;: 100},

{&#39;field&#39;: &#39;mmin_price&#39;, &#39;text&#39;: &#39;次底价&#39;, &#39;width&#39;: 100},

{&#39;field&#39;: &#39;mmin_price_num&#39;, &#39;text&#39;: &#39;盒数&#39;, &#39;width&#39;: 100},

{&#39;field&#39;: &#39;mmmin_price&#39;, &#39;text&#39;: &#39;次次低价&#39;, &#39;width&#39;: 100},

{&#39;field&#39;: &#39;mmmin_price_num&#39;, &#39;text&#39;: &#39;盒数&#39;, &#39;width&#39;: 100},

{&#39;field&#39;: &#39;company_num&#39;, &#39;text&#39;: &#39;零售厂家数量&#39;, &#39;width&#39;: 100},

]

for idx, info in enumerate(table_header):

item = QTableWidgetItem()

item.setText(f&#39;{info["text"]}&#39;)

tab.setHorizontalHeaderItem(idx, item)

tab.setColumnWidth(idx, info["width"])

form_layout.addWidget(tab)

return form_layout

# 点击开始,弹出让用户输入表格路径的小窗口

def event_btn_start(self):

self.terminate = False

dialog = InputQDialog()

dialog.setWindowModality(Qt.ApplicationModal)

dialog.listHao.connect(self.init_task_listHao_callback)

dialog.exec_()

# 停止,将停止标识改为True

def event_btn_end(self):

self.thread.terminter = True

# 小窗口点击保存后执行这个,用于创建爬虫线程,执行爬虫

def init_task_listHao_callback(self, list):

if not self.input_exclude_name.text().strip():

shopname = &#39;&#39;

else:

shopname = self.input_exclude_name.text().strip()

if not self.input_exclude_court.text().strip():

excount = 0

else:

try:

excount = int(self.input_exclude_court.text().strip())

except:

QMessageBox.warning(self, "错误", "请在排除的数量里输入一个整数")

D_list = list

print(D_list)

self.thread = thread = NewTaskTread(D_list, shopname, excount, self)

thread.success.connect(self.init_task_success_callback)

thread.error1.connect(self.init_task_error1_callback)

thread.error2.connect(self.init_task_error2_callback)

thread.start()

# 爬虫执行成功,用于展示数据

def init_task_success_callback(self, list):

current_row_count = self.tab.rowCount()

self.tab.insertRow(current_row_count)

cell = QTableWidgetItem(str(current_row_count+1))

self.tab.setItem(current_row_count, 0, cell)

for i, content in enumerate(list):

cell = QTableWidgetItem(str(content))

self.tab.setItem(current_row_count, i+1, cell)

# 失败,异常处理

def init_task_error1_callback(self, message):

print(&#39;error1:&#39;, message)

# 失败,异常处理

def init_task_error2_callback(self, message):

print(&#39;error2:&#39;, message)

# 点击开始,弹出下面的子输入框,供用户输入表格路径

class InputQDialog(QDialog):

listHao = pyqtSignal(list)

def __init__(self):

super().__init__()

self.init_ui()

def init_ui(self):

self.resize(300, 150)

self.setWindowTitle(&#39;导入表格配置&#39;)

layout = QVBoxLayout()

hider = QVBoxLayout()

label = QLabel("请输入想要导入的表格地址:", self)

hider.addWidget(label)

self.input_lint = input_lint = QLineEdit()

input_lint.setText("F:\桌面\国标编号text.xlsx")

hider.addWidget(input_lint)

Dlayout = QHBoxLayout()

Dlayout.addStretch()

btn_SAVE = QPushButton(&#39;保存&#39;)

btn_SAVE.clicked.connect(self.event_save_click)

Dlayout.addWidget(btn_SAVE)

layout.addLayout(hider)

layout.addLayout(Dlayout)

self.setLayout(layout)

# 根据路径读取表格数据,提取其中的“国标编号”列

def event_save_click(self):

path = self.input_lint.text().strip()

if not path:

QMessageBox.warning(self, "错误", "所填内容不能为空")

return

df = pd.read_excel(path)

ColNames = df.columns.tolist()

# print(ColNames)

if &#39;国标编号&#39; not in ColNames:

QMessageBox.warning(self, "错误", "所选表格不含国标编号的列名!")

return

  

list_hao = list(set([str(hao).strip() for hao in df[&#39;国标编号&#39;].tolist()]))

self.listHao.emit(list_hao)

self.close()

# 输入框输入路径后,点击保存,创建如下线程类,线程执行爬虫

class NewTaskTread(QThread):

success = pyqtSignal(list)

error1 = pyqtSignal(str)

error2 = pyqtSignal(str)

def __init__(self, list, shopname, excount, *args, **kwargs):

super().__init__(*args, **kwargs)

self.list = list

self.shopname = shopname

self.excount = excount

self.terminter = False

def run(self):

ua = UserAgent() # 生成假的浏览器请求头,防止被封ip

user_agent = ua.random # 随机选择一个浏览器

headers = {

&#39;User-Agent&#39;: user_agent,

}

for Approval_number in self.list:

print(&#39;正在爬取:&#39;, Approval_number)

# 搜索国标编号,得到翻页的页数

url_page = f&#39;https://www.yaofangwang.com/search.html?keyword={Approval_number}&#39;

r1_page = requests.get(url=url_page, headers=headers)

r1_page.encoding = "utf-8"

page_sourse1 = r1_page.text

treepage = etree.HTML(page_sourse1)

allCount = treepage.xpath(&#39;//span[@class="result"]/b/text()&#39;)[0]

allPage = int(int(allCount) / 40 + 1)

# 如果搜到的药品数量为零,打印异常

if allCount == &#39;0&#39;:

mainmessage = &#39;{}未有相关信息&#39;.format(Approval_number)

self.error2.emit(mainmessage)

continue

# 翻页处理

for mainpage in range(1, allPage + 1):

url = f&#39;https://www.yaofangwang.com/search.html?keyword={Approval_number}&page={mainpage}&#39;

r1 = requests.get(url=url, headers=headers)

r1.encoding = "utf-8"

page_sourse1 = r1.text

tree1 = etree.HTML(page_sourse1)

li_list = tree1.xpath(&#39;//ul[@class="goodlist_search clearfix"]/li&#39;)

for j, li in enumerate(li_list):

# 若点击停止,self.terminter = True

if self.terminter:

return

try:

params = {

&#39;sort&#39;: &#39;sprice&#39;,

&#39;sorttype&#39;: &#39;asc&#39;

}

detail_url = &#39;https://&#39; + li.xpath(&#39;./div/a/@href&#39;)[0][2:]

r2 = requests.get(url=detail_url, params=params, headers=headers)

r2.encoding = "utf-8"

page_sourse2 = r2.text

tree2 = etree.HTML(page_sourse2)

name = tree2.xpath(&#39;//h1[@class="clearfix pr0"]/strong/span/text()&#39;)[0]

Packaging = \

tree2.xpath(&#39;//div[@class="info clearfix"]/dl[@class="clearfix"]/dd[3]/div/div/text()&#39;)[0]

Companies = tree2.xpath(&#39;//div[@class="info clearfix"]/dl[@class="clearfix"]/dd[5]/text()&#39;)[0]

count = tree2.xpath(&#39;//ul[@class="navul"]/li/a/text()&#39;)[0].split(&#39;个&#39;)[0]

page_num = math.ceil(int(count) / 10)

info = []

for page in range(1, page_num + 1):

detail_url2 = &#39;https://&#39; + li.xpath(&#39;./div/a/@href&#39;)[0][2:] + f&#39;p{page}/&#39;

r3 = requests.get(url=detail_url2, params=params, headers=headers)

r3.encoding = "utf-8"

page_sourse3 = r3.text

tree3 = etree.HTML(page_sourse3)

li_list3 = tree3.xpath(&#39;//ul[@class="slist"]/li&#39;)

if len(info) >= 3:

break

for li2 in li_list3:

ShopName = li2.xpath(&#39;./div[@class="shop"]/p/a/@title&#39;)[0]

Stock = li2.xpath(&#39;./div[@class="info"]/p[3]/span/label/text()&#39;)[0]

Price = li2.xpath(&#39;./div[@class="sale"]/p/text()&#39;)[0].split(&#39;¥&#39;)[-1].strip()

if int(Stock)

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线