#main.py
import tkinter as tk
import bilian
from time import *
class Climbgui():
def __init__(self,windows):
self.tk_window = windows
def init_windows(self):
self.tk_window.title('爬取招标信息界面')
self.tk_window.geometry('300x350+760+280')
self.climb_excute_key_label = tk.Label(master=self.tk_window,text='请输入要爬取的招标关键词')
self.climb_excute_key_entry = tk.Entry(master=self.tk_window,width=20)
self.climb_excute_page_label = tk.Label(master=self.tk_window,text='请输入要爬取的页数')
self.climb_excute_page_entry = tk.Entry(master=self.tk_window,width=20)
self.climb_excute_key_label.grid(row=1,column=0)
self.climb_excute_key_entry.grid(row=2,column=0)
self.climb_excute_page_label.grid(row=1,column=1)
self.climb_excute_page_entry.grid(row=2,column=1)
self.climb_excute_button = tk.Button(master=self.tk_window,text='爬取',width=10,height=1,command=self.climb)
self.climb_excute_button.grid(row=3,column=0,columnspan=4,pady=5)
self.climb_result_label = tk.Label(master=self.tk_window,text='执行结果')
self.climb_result_label.grid(row=4,column=0,columnspan=4)
self.climb_result_entry = tk.Text(master=self.tk_window,width=40,height=18)
self.climb_result_entry.grid(row=5,column=0,columnspan=4)
def climb(self):
bilian.climbnum = 0
key = self.climb_excute_key_entry.get().strip()
page = int(self.climb_excute_page_entry.get().strip())
begin_time = time()
bilian.start_climb(key=key,pages=page)
end_time = time()
total_time = str(end_time-begin_time)
self.climb_result_entry.delete(1.0, 'end')
self.climb_result_entry.insert(1.0, '本次共爬取招标信息:'+str(bilian.climbnum)+'条。')
self.climb_result_entry.delete(2.0, 'end')
self.climb_result_entry.insert(2.0, '\n本次爬取关键词为:'+key+',爬取总页数为:'+str(page)+'。')
self.climb_result_entry.delete(3.0, 'end')
self.climb_result_entry.insert(3.0, '\n本次爬取结果已保存到文件:result.csv。')
self.climb_result_entry.delete(4.0, 'end')
self.climb_result_entry.insert(4.0, '\n本次爬取总运行时间:'+total_time+'s。')
if __name__ == '__main__':
windows = tk.Tk()
gui = Climbgui(windows)
gui.init_windows()
windows.mainloop()
#bilian.py
import re
import requests
from lxml import etree
import csv
# 存储总共爬取的条数
climbnum = 0
# 存储的数据格式
sql_data = dict(
web = '', #信息来源网站
keyword = '', #关键字
detail_url = '', #招标详细页网址
title = '', #第三方网站发布标题
toptype = '', #信息类型
province = '', #归属省份
prodect = '', #产品范畴
tendering_manner = '', #招标方式
publicity_date = '', #招标公示日期
expiry_date = '', #招标截止时间
)
#csv文件的表头
CSVHEADER = ['web','keyword','detail_url','title','toptype','province','prodect','tendering_manner','publicity_date','expiry_date']
#请求时带的数据
params = dict(
infoClassCodes='',
rangeType='',
projectType='bid',
fundSourceCodes='',
dateType='',
startDateCode='',
endDateCode='',
normIndustry='',
normIndustryName='',
zone='',
zoneName='',
zoneText='',
key='', # keyword
pubDateType='',
pubDateBegin='',
pubDateEnd='',
sortMethod='timeDesc',
orgName='',
currentPage='1', # page
)
DEFAULT_REQUEST_HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36',
'Host':'ss.ebnew.com',
'cookie':'loginUser=; __cfduid=daa1311ae7cd31fd395f7e3251e7770671608880455; Hm_lvt_ce4aeec804d7f7ce44e7dd43acce88db=1608880460; JSESSIONID=5644896A631BE3652EA3853BEE69DF00; Hm_lpvt_ce4aeec804d7f7ce44e7dd43acce88db=1608881105'
}
COOKIES = 'loginUser=; __cfduid=daa1311ae7cd31fd395f7e3251e7770671608880455; Hm_lvt_ce4aeec804d7f7ce44e7dd43acce88db=1608880460; JSESSIONID=5644896A631BE3652EA3853BEE69DF00; Hm_lpvt_ce4aeec804d7f7ce44e7dd43acce88db=1608881105'
def write_csv(datas):
global CSVHEADER
with open('result.csv','a',newline='',encoding='utf-8') as f1:
writer = csv.DictWriter(f1,fieldnames=CSVHEADER)
with open("result.csv", "r", newline="",encoding='utf-8') as f2:
reader = csv.reader(f2)
# 判断是否存在标题,不存在则写入标题
if not [row for row in reader]:
writer.writeheader()
writer.writerow(datas)
else:
writer.writerow(datas)
def start_requests(keyword,page):
'''
开始请求,并返回html对象
:param self:
:return:
'''
global DEFAULT_REQUEST_HEADERS
global params
params['key'] = keyword
params['currentPage'] = page
try:
response = requests.get(
url='https://ss.ebnew.com/tradingSearch/index.htm',
params=params,
headers=DEFAULT_REQUEST_HEADERS
)
html = etree.HTML(response.text)
return html
except:
print('未知错误')
return None
def pagenum_get(html):
'''
用于提取总页数
:param html:
:return:
'''
page_num = html.xpath('//form[@id="pagerSubmitForm"]/a/text()')
if page_num:
return page_num
def pagedata_get(html):
global sql_data
global params
global climbnum
content_list_x_s = html.xpath('//div[@class="ebnew-content-list"]/div')
for content_list_x in content_list_x_s:
toptype = content_list_x.xpath('./div/i[1]/text()')
title = content_list_x.xpath('./div/a/text()')
publicity_date = content_list_x.xpath('./div/i[2]/text()')
tendering_manner = content_list_x.xpath('./div[2]/div[1]/p[1]/span[2]/text()')
prodect = content_list_x.xpath('./div[2]/div[1]/p[2]/span[2]/text()')
expiry_date = content_list_x.xpath('./div[2]/div[2]/p[1]/span[2]/text()')
province = content_list_x.xpath('./div[2]/div[2]/p[2]/span[2]/text()')
sql_data['toptype'] = toptype[0] if toptype else None
sql_data['title'] = title[0] if title else None
sql_data['publicity_date'] = publicity_date[0] if publicity_date else None
if sql_data['publicity_date']:
sql_data['publicity_date'] = re.sub('[^0-9\-]', '', sql_data['publicity_date'])
sql_data['tendering_manner'] = tendering_manner[0] if tendering_manner else None
sql_data['prodect'] = prodect[0] if prodect else None
sql_data['expiry_date'] = expiry_date[0] if expiry_date else None
sql_data['province'] = province[0] if province else None
sql_data['keyword'] = params['key']
sql_data['web'] = '必联网'
sql_data['detail_url'] = content_list_x.xpath('./div/a/@href')[0] if content_list_x.xpath('./div/a/@href') else None
write_csv(sql_data)
climbnum += 1
def start_climb(key,pages):
'''
图形界面的开始爬取集合方法
:param key:
:param page:
:return:
'''
for page in range(1,pages+1):
print(page)
pagedata_get(start_requests(keyword=key,page=page))
print('已经完成第'+str(page)+'页爬取!')
报告
目录
1 引言 1
1.1 课题背景 1
1.2 所用技术 1
2 系统分析 2
3 系统设计 2
3.1 结构分析 2
3.2 数据库设计 3
4 系统实现 4
4.1 步骤及截图 4
4.2 代码实现 6
5 结束语 9
学生信息管理系统
1 引言
1.1 课题背景
必联网是服务于招标机构、采购业主和投标商的电子招投标交易平台。服务范围涵盖了国际和国内招标的设备类、物资类、工程类、服务类等多种招标业务,其开放式平台接口可以兼容企业内部管理系统和招投标应用系统,可对接国家各级公共服务平台、行政监督平台,实现了企业内部管理。作为一个公平、公正、公开的互联网采购与招标管理平台,必联网凭借在采购与招标领域的十年研究,积累了丰富的实践经验。也因此给广大企业提供了便捷、高效的互联网采购管理技术和行业信息资讯服务,从而成就了整个采购产业链的高速流畅运转,促进采供双方的良性合作,创造了一个共享、共赢的市场环境。必联网是“全方位的资讯服务+多效的采购交易平台+管家式服务”为一体的企业采购协同工作平台。不仅有日均数万的招标采购和企业产品信息,还支持企业的在线交易协同,面积分,支持以项目管理为核心的交易统计和资源管理等功能,帮助用户实现一体化的采购供应管理。必联网给用户真实的在线推广和业务管理环境,其平台化的作业方式不仅降低企业电子商务进入成本,而且大大提高企业采供协同效率,帮助企业合理配置业务资源,拓展更多商业机会。
该软件是用来爬取必联网的招标信息,用来帮助企业来收集招标信息,比如企业的产品为计算机,它可以通过这个软件来搜索到大量计算机的招标信息 ,然后进行投标增加企业收入。
1.2 所用技术
Python是一种开源的、解析性的,面向对象的语言编程。它语法优雅,可读性强,让程序员注重功能实现,而非代码本身实现细节。现广泛运用于Web开发、运维自动化、测试自动化及数据挖掘等多个行业和领域。Python语言有很大的优势:比Java、C++简单更易于使用;比PHP易懂易学并且用途更广;比Perl更简洁的语法、更简单的设计,更具可读性、更易于维护,有助于减少Bug。但它的性能不如Java、C、C++这类编译性语言强大。因此本系统开发选用Python语言编写。
界面采用tkinter框架:
Tkinter: Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 .Tk 和 Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里。Tk8.0 的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。
爬取采用results和lxml:
lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高。
参考资料:https://blog.csdn.net/cz9025/article/details/87914169
2 系统分析
本次设计用Eclipse、Django开发工具,Python语言进行学生信息管理系统的开发,主要功能有后台进行建表,与数据库同步,在数据库中存储学生信息,并有增加、删除、修改功能;用户可以通过网址输入自己的登录姓名和学号,查询其余信息。分为管理端和客户端:
管理端:管理员在后台进行学生信息增加、删除、修改等功能,将学生信息保存进数据库。
客户端:用户通过管理员给定的网址进入查询页面,输入姓名与学号查询自己的信息。
3 系统设计
3.1 结构分析
(1)根据系统分析,画出系统功能模块结构图:
图 3.1 系统功能模块结构图
(2)画出系统模块功能流程图:
图 3.2 系统功能模块流程图
3.2 数据库设计
对招标信息进行存储,用到了一张表格,如果还需要其他信息,可进行表格增加。
表1 招标详细信息
列名 功能描述 类型 字段大小 主键否
web 信息来源网站 varchar 150 否
keyword 关键字 varchar 150 否
detail_url 招标详细页网址 varchar 150 否
title 第三方发布标题 varchar 150 否
toptype 信息类型 varchar 150 否
province 归属省份 varchar 150 否
prodect 产品范畴 varchar 150 否
tendering_manner 招标方式 varchar 150 否
publicity_date 招标公示日期 varchar 150 否
expiry_date 招标截止时间 varchar 150 否
4 系统实现
4.1 步骤及截图
(1) 通过编写main.py用tkinter架构建立界面并显示:
图 4.1 建立界面
(2)爬取使用results和lxml
(3)运行结果保存至csv文件:
图 4.2 保存的招标信息
4.2 代码实现
(1)在main.py中建立一个Climbgui类,用于爬取信息,显示爬取详情,以及保存爬取信息。
class Climbgui():
def init(self,windows):
self.tk_window = windows
def init_windows(self):
self.tk_window.title('爬取招标信息界面')
self.tk_window.geometry('300x350+760+280')
self.climb_excute_key_label = tk.Label(master=self.tk_window,text='请输入要爬取的招标关键词')
self.climb_excute_key_entry = tk.Entry(master=self.tk_window,width=20)
self.climb_excute_page_label = tk.Label(master=self.tk_window,text='请输入要爬取的页数')
self.climb_excute_page_entry = tk.Entry(master=self.tk_window,width=20)
self.climb_excute_key_label.grid(row=1,column=0)
self.climb_excute_key_entry.grid(row=2,column=0)
self.climb_excute_page_label.grid(row=1,column=1)
self.climb_excute_page_entry.grid(row=2,column=1)
self.climb_excute_button = tk.Button(master=self.tk_window,text='爬取',width=10,height=1,command=self.climb)
self.climb_excute_button.grid(row=3,column=0,columnspan=4,pady=5)
self.climb_result_label = tk.Label(master=self.tk_window,text='执行结果')
self.climb_result_label.grid(row=4,column=0,columnspan=4)
self.climb_result_entry = tk.Text(master=self.tk_window,width=40,height=18)
self.climb_result_entry.grid(row=5,column=0,columnspan=4)
def climb(self):
bilian.climbnum = 0
key = self.climb_excute_key_entry.get().strip()
page = int(self.climb_excute_page_entry.get().strip())
begin_time = time()
bilian.start_climb(key=key,pages=page)
end_time = time()
total_time = str(end_time-begin_time)
self.climb_result_entry.delete(1.0, 'end')
self.climb_result_entry.insert(1.0, '本次共爬取招标信息:'+str(bilian.climbnum)+'条。')
self.climb_result_entry.delete(2.0, 'end')
self.climb_result_entry.insert(2.0, '\n本次爬取关键词为:'+key+',爬取总页数为:'+str(page)+'。')
self.climb_result_entry.delete(3.0, 'end')
self.climb_result_entry.insert(3.0, '\n本次爬取结果已保存到文件:result.csv。')
self.climb_result_entry.delete(4.0, 'end')
self.climb_result_entry.insert(4.0, '\n本次爬取总运行时间:'+total_time+'s。')
(2)write_csv 方法是用来把结果保存到csv中
def write_csv(datas):
global CSVHEADER
with open(‘result.csv’,‘a’,newline=’’,encoding=‘utf-8’) as f1:
writer = csv.DictWriter(f1,fieldnames=CSVHEADER)
with open(“result.csv”, “r”, newline="",encoding=‘utf-8’) as f2:
reader = csv.reader(f2)
# 判断是否存在标题,不存在则写入标题
if not [row for row in reader]:
writer.writeheader()
writer.writerow(datas)
else:
writer.writerow(datas)
(3)start_requests方法用来开始请求并返回一个html对象
def start_requests(keyword,page):
‘’’
开始请求,并返回html对象
:param self:
:return:
‘’’
global DEFAULT_REQUEST_HEADERS
global params
params[‘key’] = keyword
params[‘currentPage’] = page
try:
response = requests.get(
url=‘https://ss.ebnew.com/tradingSearch/index.htm’,
params=params,
headers=DEFAULT_REQUEST_HEADERS
)
html = etree.HTML(response.text)
return html
except:
print(‘未知错误’)
return None
(4)pagedata_get方法是用来提取页面的数据信息
def pagedata_get(html):
global sql_data
global params
global climbnum
content_list_x_s = html.xpath(’//div[@class=“ebnew-content-list”]/div’)
for content_list_x in content_list_x_s:
toptype = content_list_x.xpath(’./div/i[1]/text()’)
title = content_list_x.xpath(’./div/a/text()’)
publicity_date = content_list_x.xpath(’./div/i[2]/text()’)
tendering_manner = content_list_x.xpath(’./div[2]/div[1]/p[1]/span[2]/text()’)
prodect = content_list_x.xpath(’./div[2]/div[1]/p[2]/span[2]/text()’)
expiry_date = content_list_x.xpath(’./div[2]/div[2]/p[1]/span[2]/text()’)
province = content_list_x.xpath(’./div[2]/div[2]/p[2]/span[2]/text()’)
sql_data['toptype'] = toptype[0] if toptype else None
sql_data['title'] = title[0] if title else None
sql_data['publicity_date'] = publicity_date[0] if publicity_date else None
if sql_data['publicity_date']:
sql_data['publicity_date'] = re.sub('[^0-9\-]', '', sql_data['publicity_date'])
sql_data['tendering_manner'] = tendering_manner[0] if tendering_manner else None
sql_data['prodect'] = prodect[0] if prodect else None
sql_data['expiry_date'] = expiry_date[0] if expiry_date else None
sql_data['province'] = province[0] if province else None
sql_data['keyword'] = params['key']
sql_data['web'] = '必联网'
sql_data['detail_url'] = content_list_x.xpath('./div/a/@href')[0] if content_list_x.xpath('./div/a/@href') else None
write_csv(sql_data)
climbnum += 1