目录
一、前言 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
cursor.execute( 6
2.2 UI设计 11
一、前言
1.1 背景
近几年来网络购物越来越流行,基本上每个人都有过网购经历,本着“货比三家”的原则,我们往往倾向于对商品进行大量的比较。然而不同的网购平台其商品也不尽相通,而跨网站的比较又着实比较麻烦,因此就有了做一个快捷的网购平台比价系统的想法,实现在一个界面内实现多网购平台商品的比价操作。
其实很早就萌生了做这个程序的念头,但是一直都觉得实现起来比较麻烦所以就鸽了,但是由于在做学校的Python课设时没有好的想法,就还是把这个给提了出来,真正实现之后发现也并不是很难。
1.2 用到的技术简述
既然是比价系统,就肯定要实现数据的获取,那么就难免需要网络爬虫技术、数据库技术以及简单的UI设计。
1.2.1 网络爬虫技术
我们用到的是requests+selenium的方法进行爬虫,其实简单的爬虫用不到selenium,requests就足够了,但是有些网站不是静态加载的,我们用requests就获取不到数据,因此这里也用一下selenium,以便于进行扩展。
requests:可以直接利用get方法获取目标页面的HTML文本,使用起来十分简单。
selenium:可以实现模拟操作,其操作可以做到与手动一样,从而获取页面的文本(手动操作即在页面上右键->查看源代码从而获取HTML文本),虽然可能会有点慢,但是可以很好的绕过网站的反爬虫程序。
既然已经获取到了HTML文本,那么就肯定需要进行解析,从而获取到我们想要的数据。常用的解析方法是BeautifulSoup和正则表达式re。
BeautifulSoup:利用HTML中的标签进行查找,在查找目标数据时需要观察目标数据在哪个Tag下,可以利用父Tag到子Tag的方式逐级查找,或者利用目标数据所在Tag的位置进行查找(这个方法风险比较大,网页源码稍有改动就有可能完蛋)。例如以下HTML(只是做个示例,没有详细学过HTML,可能会写错还请勿喷):
正则表达式re:具体语法就不讲了,比较麻烦,不懂的可以自己查一下,这里给一个连接:正则表达式–菜鸟教程,学起来还是比较快的,值得一提的是,在HTML中利用正则表达式时往往需要进行最短匹配(默认的匹配是贪婪匹配),这就需要我们利用好“?”这个符号。以上面的例子为例,我们可以利用正则表达式<//tag1>.* ?
1.2.2 UI设计
我们用到的是Python中的tkinter第三方库,可以很容易的实现简单的UI设计。涉及到的操作就是控件的布局、鼠标点击的响应事件、控件中数据的获取,都是一些比较简单的操作。这里简单放一下我设计的结果(设计的比较简陋,因为俺也是现学的这东西,不是很懂那些高级控件),具体操作我们后面说。文章来源:https://www.toymoban.com/news/detail-446465.html
import tkinter as tk
from tkinter import ttk
import tkinter.messagebox
from GoodsList import GoodsList
from Goods import Goods
from DBConnection import DBConnection
class 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='您未选取任何平台')
return
check_numls=[]
for i in range(60):
check_numls.append(i+1)
if number not in check_numls:
tk.messagebox.showinfo(title='提示', message='请输入正确的爬取数量(1--60)')
return
if keyword == '':
tk.messagebox.showinfo(title='提示', message='请输入关键词')
return
goodslist = 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 = '当前无商品信息')
return
else:
num = 1
for 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 == '':
continue
try:
if not isinstance(eval(num), int):
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
elif eval(num) > len(self.goodsinfo) or eval(num) < 1:
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
else:
compare_ls.append(self.goodsinfo[eval(num)-1])
except:
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
goodslist = 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 == '':
continue
try:
if not isinstance(eval(num), int):
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
elif eval(num) > len(self.goodsinfo) or eval(num) < 1:
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
else:
add_ls.append(self.goodsinfo[eval(num) - 1])
except:
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
dbc = 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 = '当前关注列表无商品')
return
else:
num = 1
for 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 == '':
continue
try:
if not isinstance(eval(num), int):
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
elif eval(num) > len(self.goodsinfo) or eval(num) < 1:
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
else:
delete_ls.append(self.goodsinfo[eval(num) - 1])
except:
tk.messagebox.showinfo(title='提示', message='请输入正确的序号')
return
dbc = 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()
文章来源地址https://www.toymoban.com/news/detail-446465.html
到了这里,关于基于网络爬虫的商品询价系统的设计与实现(Python)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!