首页 >> 大全

基于网络爬虫的商品询价系统的设计与实现(Python)

2023-08-07 大全 35 作者:考证青年

目录

一、前言 1

1.1 背景 1

1.2 用到的技术简述 1

1.2.1 网络爬虫技术 2

1.2.2 UI设计 3

1.2.3 数据库设计 3

二、设计过程 3

2.1 面向对象设计 3

2.1.1 由需求导出用例图 4

2.1.2 类的确定 4

2.1.3 实体类的设计 6

2.1.4 功能类的设计 6

.( 6

2.2 UI设计 11

一、前言

1.1 背景

近几年来网络购物越来越流行,基本上每个人都有过网购经历,本着“货比三家”的原则,我们往往倾向于对商品进行大量的比较。然而不同的网购平台其商品也不尽相通,而跨网站的比较又着实比较麻烦,因此就有了做一个快捷的网购平台比价系统的想法,实现在一个界面内实现多网购平台商品的比价操作。

其实很早就萌生了做这个程序的念头,但是一直都觉得实现起来比较麻烦所以就鸽了,但是由于在做学校的课设时没有好的想法,就还是把这个给提了出来,真正实现之后发现也并不是很难。

1.2 用到的技术简述

既然是比价系统,就肯定要实现数据的获取,那么就难免需要网络爬虫技术、数据库技术以及简单的UI设计。

1.2.1 网络爬虫技术

我们用到的是+的方法进行爬虫,其实简单的爬虫用不到,就足够了,但是有些网站不是静态加载的,我们用就获取不到数据,因此这里也用一下,以便于进行扩展。

:可以直接利用get方法获取目标页面的HTML文本,使用起来十分简单。

:可以实现模拟操作,其操作可以做到与手动一样,从而获取页面的文本(手动操作即在页面上右键->查看源代码从而获取HTML文本),虽然可能会有点慢,但是可以很好的绕过网站的反爬虫程序。

既然已经获取到了HTML文本,那么就肯定需要进行解析,从而获取到我们想要的数据。常用的解析方法是和正则表达式re。

:利用HTML中的标签进行查找,在查找目标数据时需要观察目标数据在哪个Tag下,可以利用父Tag到子Tag的方式逐级查找,或者利用目标数据所在Tag的位置进行查找(这个方法风险比较大,网页源码稍有改动就有可能完蛋)。例如以下HTML(只是做个示例,没有详细学过HTML,可能会写错还请勿喷):

a b c 比如我们想要获取tag2下的title(即b),我们可以先查找tag1,然后查找title,然后获取title中的内容;也可以直接查所有的title,在返回的列表中选择第二个,之后获取其下的内容。

正则表达式re:具体语法就不讲了,比较麻烦,不懂的可以自己查一下,这里给一个连接:正则表达式–菜鸟教程,学起来还是比较快的,值得一提的是,在HTML中利用正则表达式时往往需要进行最短匹配(默认的匹配是贪婪匹配),这就需要我们利用好“?”这个符号。以上面的例子为例,我们可以利用正则表达式.* ?.?来获取目标字符串,然后利用正则表达式.?从该字符串中扣出来仅包含目标数据的字符串,从而可以利用下标来获取指定数据,比如此处我们可以选择第8—(-8)个字符来获取目标数据“b”(-8代表倒数第8),为了防止出现错误,在每次的匹配任意多个字符的时候最好都加上"?"。

1.2.2 UI设计

我们用到的是中的第三方库,可以很容易的实现简单的UI设计。涉及到的操作就是控件的布局、鼠标点击的响应事件、控件中数据的获取,都是一些比较简单的操作。这里简单放一下我设计的结果(设计的比较简陋,因为俺也是现学的这东西,不是很懂那些高级控件),具体操作我们后面说。

import tkinter as tk
from tkinter import ttk
import tkinter.messagebox
from GoodsList import GoodsList
from Goods import Goods
from DBConnection import DBConnectionclass GUI:#用于存放商品信息goodsinfo = []#主窗口window = tk.Tk()#框架划分frm_t = tk.Frame(window, width=1000, height=300).pack()frm_b = tk.Frame(window, width=1000, height=600).pack()frm_d = tk.Frame(window, width=1000, height=100).pack()#平台选择tm_var = tk.IntVar()jd_var = tk.IntVar()pdd_var = tk.IntVar()c1 = tk.Checkbutton(frm_t, text='天猫', variable=tm_var, onvalue=1, offvalue=0)c2 = tk.Checkbutton(frm_t, text='京东', variable=jd_var, onvalue=1, offvalue=0)c3 = tk.Checkbutton(frm_t, text='拼多多', variable=pdd_var, onvalue=1, offvalue=0)#获取爬取商品数量dp_var = tk.IntVar()dp_en = tk.Entry(frm_t, textvariable=dp_var, width=3)#获取搜索关键词goods_var = tk.StringVar()goods_en = tk.Entry(frm_t, textvariable=goods_var, width=10)#排序方式sort_var = tk.IntVar()ch1 = tk.Radiobutton(frm_b, text='默认排序', variable=sort_var, value=1)ch2 = tk.Radiobutton(frm_b, text='价格升序', variable=sort_var, value=2)ch3 = tk.Radiobutton(frm_b, text='价格倒序', variable=sort_var, value=3)# 获取序号num_var = tk.StringVar()num_en = tk.Entry(frm_t, textvariable=num_var, width=50)#表格tree = ttk.Treeview(frm_d, columns=['1', '2', '3', '4', '5', '6', '7', '8'], show='headings', height=25)#表格滚动条VScroll1 = ttk.Scrollbar(tree, orient='vertical', command=tree.yview)#这个按钮后面在函数中需要变动,所以设为全局变量comfirm3 = tk.Button(frm_t, text='加入关注',  width=20)#获取信息def getInfo(self):self.comfirm3.config(text = '加入关注',command=self.addtoDB)self.goodsinfo.clear()tm = self.tm_var.get()jd = self.jd_var.get()pdd = self.pdd_var.get()number = self.dp_var.get()keyword = self.goods_var.get()if not tm and not jd and not pdd:tk.messagebox.showinfo(title='提示', message='您未选取任何平台')returncheck_numls=[]for i in range(60):check_numls.append(i+1)if number not in check_numls:tk.messagebox.showinfo(title='提示', message='请输入正确的爬取数量(1--60)')returnif keyword == '':tk.messagebox.showinfo(title='提示', message='请输入关键词')returngoodslist = GoodsList(keyword,number,tmall=tm,jd=jd,pdd=pdd)goodslist.getGoods()if self.sort_var.get() == 1:self.goodsinfo.extend(goodslist.getGoodsList())elif self.sort_var.get() == 2:self.goodsinfo.extend(goodslist.sort())else:self.goodsinfo.extend(goodslist.sort(reverse = True))self.showdata()tk.messagebox.showinfo(title='提示', message='爬取完成\n*拼多多商品销量为总销量,天猫销量为月销量')#显示信息def showdata(self):for item in self.tree.get_children():self.tree.delete(item)if not self.goodsinfo:tk.messagebox.showinfo(title = '提示',message = '当前无商品信息')returnelse:num = 1for goods in self.goodsinfo:goodslist = [num,goods.getID(),goods.getPlatform(),goods.getTitle(),goods.getShop(),goods.getPrice(),goods.getSales(),goods.getHref()]self.tree.insert('','end',values = goodslist)num = num+1#比价def compare(self):num_ls = self.num_var.get().split(' ')num_ls = list(set(num_ls))compare_ls = []for num in num_ls:if num == '':continuetry:if not isinstance(eval(num), int):tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returnelif eval(num) > len(self.goodsinfo) or eval(num) < 1:tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returnelse:compare_ls.append(self.goodsinfo[eval(num)-1])except:tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returngoodslist = GoodsList('', 0)result = goodslist.compare(compare_ls)tk.messagebox.showinfo(title='比价结果', message=result)#加入关注列表def addtoDB(self):num_ls = self.num_var.get().split(' ')num_ls = list(set(num_ls))add_ls = []for num in num_ls:if num == '':continuetry:if not isinstance(eval(num), int):tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returnelif eval(num) > len(self.goodsinfo) or eval(num) < 1:tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returnelse:add_ls.append(self.goodsinfo[eval(num) - 1])except:tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returndbc = DBConnection()result = ''for item in add_ls:if dbc.save(item):result = result + '\"' + item.getTitle() + '\" 已成功加入关注列表\n'else:result = result + '\"' + item.getTitle() + '\" 已在关注列表中\n'tk.messagebox.showinfo(title='提示', message=result)#显示关注列表def showDB(self):self.comfirm3.config(text='移除关注', command=self.delete)self.goodsinfo = []dbc = DBConnection()g_ls = dbc.getInfo()for item in g_ls:goods = Goods(item[0],item[1],item[2],item[3],item[4],item[5],item[6])self.goodsinfo.append(goods)for item in self.tree.get_children():self.tree.delete(item)if not self.goodsinfo:tk.messagebox.showinfo(title = '提示',message = '当前关注列表无商品')returnelse:num = 1for goods in self.goodsinfo:li = [num,goods.getID(),goods.getPlatform(),goods.getTitle(),goods.getShop(),goods.getPrice(),goods.getSales(),goods.getHref()]self.tree.insert('','end',values =li)num = num+1#更新关注列表内容def updateDB(self):change_ls = []dbc = DBConnection()self.goodsinfo = []g_ls = dbc.getInfo()for item in g_ls:goods = Goods(item[0], item[1], item[2], item[3], item[4], item[5], item[6])self.goodsinfo.append(goods)for item in self.goodsinfo:change = item.update()if change != 0:change_ls.append([item.getTitle(),change])if change_ls:s = ''for item in change_ls:if item[1]>0:s = s + '\"' + item[0] + '\" 价格增加了 ' + str(item[1]) + ' 元\n'else:s = s + '\"' + item[0] + '\" 价格降低了 ' + str(abs(item[1])) + ' 元\n'else:s = '关注列表中所有商品价格均无变动'tk.messagebox.showinfo(title='提示', message=s)#从关注列表删除def delete(self):num_ls = self.num_var.get().split(' ')num_ls = list(set(num_ls))delete_ls = []for num in num_ls:if num == '':continuetry:if not isinstance(eval(num), int):tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returnelif eval(num) > len(self.goodsinfo) or eval(num) < 1:tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returnelse:delete_ls.append(self.goodsinfo[eval(num) - 1])except:tk.messagebox.showinfo(title='提示', message='请输入正确的序号')returndbc = DBConnection()for item in delete_ls:dbc.delete(item)tk.messagebox.showinfo(title='提示', message='删除成功')#主窗口def mainwindow(self):self.window.title('网购平台比价系统')self.window.geometry('1150x700')# 网站选择tk.Label(self.frm_t, text='平台选择:').place(x=30, y=30)self.c1.place(x=100, y=28)self.tm_var.set(True)self.c2.place(x=170, y=28)self.jd_var.set(True)self.c3.place(x=240, y=28)self.pdd_var.set(True)# 商品数选择tk.Label(self.frm_t, text='每个平台爬取数量:').place(x=330, y=30)self.dp_en.place(x=445, y=30)self.dp_var.set(1)# 商品选择tk.Label(self.frm_t, text='关键词:').place(x=500, y=30)self.goods_en.place(x=555, y=30)# 排序tk.Label(self.frm_b, text='排序方式:').place(x=655, y=30)self.sort_var.set(1)self.ch1.place(x=720, y=30)self.ch2.place(x=800, y=30)self.ch3.place(x=880, y=30)# 商品选择tk.Label(self.frm_b, text='请输入序号:').place(x=30, y=90)self.num_en.place(x=105, y=90)self.num_var.set('(提示:若输入多个序号请用空格隔开)')# 确认comfirm1 = tk.Button(self.frm_t, text='开始爬取', command=self.getInfo, width=20)comfirm1.place(x=980, y=30)# 开始比价comfirm2 = tk.Button(self.frm_t, text='开始比价',command=self.compare, width=20)comfirm2.place(x=500, y=90)# 加入关注列表self.comfirm3.config(command=self.addtoDB)self.comfirm3.place(x=660, y=90)# 显示关注列表comfirm4 = tk.Button(self.frm_t, text='关注列表',command=self.showDB,width=20)comfirm4.place(x=820, y=90)# 更新关注列表comfirm4 = tk.Button(self.frm_t, text='更新关注商品价格',command=self.updateDB, width=20)comfirm4.place(x=980, y=90)# 划线canvas1 = tk.Canvas(self.frm_b, bg='white', width=1095, height=3)canvas1.place(x=30, y=130)canvas2 = tk.Canvas(self.frm_b, bg='white', width=1095, height=3)canvas2.place(x=30,y=70)# 打印表格头部self.tree.column('1', width=50, anchor='w')self.tree.heading('1', text='序号')self.tree.column('2', width=100, anchor='w')self.tree.heading('2', text='ID')self.tree.column('3', width=80, anchor='w')self.tree.heading('3', text='平台')self.tree.column('4', width=300, anchor='w')self.tree.heading('4', text='标题')self.tree.column('5', width=150, anchor='w')self.tree.heading('5', text='商铺')self.tree.column('6', width=80, anchor='w')self.tree.heading('6', text='价格')self.tree.column('7', width=80, anchor='w')self.tree.heading('7', text='销量')self.tree.column('8', width=255, anchor='w')self.tree.heading('8', text='链接')self.VScroll1.place(relx=0.979, rely=0, relwidth=0.020, relheight=1)self.tree.configure(yscrollcommand=self.VScroll1.set)self.tree.place(x=30, y=150)self.window.mainloop()if __name__ =='__main__':ui = GUI()ui.mainwindow()

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了