分类

课内:
不限
类型:
不限 游戏 项目 竞赛 个人研究 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
年份:
不限 2018 2019 2020 2021

资源列表

  • 基于python的网易云音乐分析


    MacOS Sierra 10.12.1
    Python 2.7
    selenium 3.4.3
    phantomjs

    前言
    发现自己有时候比挖掘别人来的更加有意义,自己到底喜欢谁的歌,自己真的知道么?习惯不会骗你

    搭建爬虫环境1.安装seleniumpip install selenium# anaconda环境的可用conda install selenium# 网速不好的可用到https://pypi.python.org/pypi/selenium下载压缩包,解压后使用python setup.py install
    2.安装Phantomjs2.1 Mac版本步骤一下载包:去这里下载对应版本http://phantomjs.org/download.html步骤二解压:双击就行,用unzip这都无所谓步骤三切入路径:cd ~/Downloads/phantomjs-2.1.1-macosx/bin # 我下的路径的路径是download,版本不一,注意修改步骤四:chmod +x phantomjs步骤五: 配置环境,因为我装的的zsh,所以文件需要修改的是~/.zshrc这个文件,加上这句话export PATH="/Users/mrlevo/Downloads/phantomjs-2.1.1-macosx/bin/:$PATH",然后source ~/.zshrc 即可生效(没用zsh的同学,直接修改的文件时~/.bash_profile,添加内容和上述一致)查看是否生效:phantomjs -v # 有信息如 2.1.1 则生效mac若遇到问题请参考PhantomJS 安装
    2.2 Win版本官网http://phantomjs.org/下载PhantomJS解压后如下图所示:

    调用时可能会报错“Unable to start phantomjs with ghostdriver”如图:



    此时可以设置下Phantomjs的路径,同时如果你配置了Scripts目录环境变量,可以解压Phantomjs到该文件夹下。可参考Selenium with GhostDriver in Python on Windows - stackoverflow,整个win安装过程可参考在Windows下安装PIP+Phantomjs+Selenium],Mac和Linux/Ubuntu 下可参考[解决:Ubuntu(MacOS)+phantomjs+python的部署问题

    3. 测试安装是否成功# 进入python环境后执行如下操作# win下操作>>> from selenium import webdriver # pip install selenium>>> driver_detail = webdriver.PhantomJS(executable_path="F:\Python\phantomjs-1.9.1-windows\phantomjs.exe")>>> driver_detail.get('https://www.baidu.com')>>> news = driver_detail.find_element_by_xpath("//div[@id='u1']/a")>>> print news.text新闻>>> driver_detail.quit() # 记得关闭,不然耗费内存------------------------------------------------------------------------# mac下操作>>> from selenium import webdriver # pip install selenium>>> driver_detail = webdriver.PhantomJS()>>> driver_detail.get('https://www.baidu.com')>>> news = driver_detail.find_element_by_xpath("//div[@id='u1']/a")>>> print news.text新闻>>> driver_detail.quit() # 记得关闭,不然耗费内存爬取动态数据
    获取自己的id号,这个可以自己登陆自己的网易云音乐后获得,就是id=后面那个值



    构造爬取的id,因为我发现,每个人的id只要被获取到,他的歌单都是公开的!!!这就节省了自动登录的一步,而且,我还有个大胆的想法,哈哈哈,我还要搞个大新闻!这次先不说~

    墙裂推荐先阅读该博客掌握获取元素方法:Python爬虫 Selenium实现自动登录163邮箱和Locating Elements介绍
    # -*- coding: utf-8 -*-import tracebackfrom selenium import webdriverimport selenium.webdriver.support.ui as uifrom selenium.webdriver.common.desired_capabilities import DesiredCapabilitiesimport timeimport random# 存储为文本的子函数def write2txt(data,path): f = open(path,"a") f.write(data) f.write("\n") f.close()# 获取该id喜欢音乐的列表def catchSongs(url_id,url): user = url_id.split('=')[-1].strip() print 'excute user:',user driver = webdriver.PhantomJS()#,executable_path='/Users/mrlevo/phantomjs-2.1.1-macosx/bin/phantomjs') # 注意填上路径 driver.get(url) driver.switch_to_frame('g_iframe') # 网易云的音乐元素都放在框架内!!!!先切换框架 try: wait = ui.WebDriverWait(driver,15) wait.until(lambda driver: driver.find_element_by_xpath('//*[@class="j-flag"]/table/tbody')) # 等待元素渲染出来 try: song_key = 1 wrong_time = 0 while wrong_time < 5: # 不断获取歌信息,假定5次获取不到值,就判无值可获取,跳出循环 try: songs = driver.find_elements_by_xpath('//*[@class="j-flag"]/table/tbody/tr[%s]'%song_key) info_ = songs[0].text.strip().split("\n") if len(info_) == 5: info_.insert(2,'None') # 没有MV选项的进行插入None new_line = '%s|'%user+'|'.join(info_) song_key +=1 #new_line = "%s|%s|%s|%s|%s|%s|%s"%(user,info_[0],info_[1],info_[2],info_[3],info_[4],info_[5]) print new_line write2txt(new_line.encode('utf-8'),user) # mac写入文件需要改变字符,以id命名的文件,存储在执行脚本的当前路径下,在win下请去掉编.endcode('utf-8') except Exception as ex: wrong_time +=1 # print ex except Exception as ex: pass except Exception as ex: traceback.print_exc() finally: driver.quit()# 获取id所喜爱的音乐的urldef catchPlaylist(url): driver = webdriver.PhantomJS()#,executable_path='/Users/mrlevo/phantomjs-2.1.1-macosx/bin/phantomjs') # 注意填上路径 driver.get(url) driver.switch_to_frame('g_iframe') # 网易云的音乐元素都放在框架内!!!!先切换框架 try: wait = ui.WebDriverWait(driver,15) wait.until(lambda driver: driver.find_element_by_xpath('//*[@class="m-cvrlst f-cb"]/li[1]/div/a')) # 根据xpath获取元素 urls = driver.find_elements_by_xpath('//*[@class="m-cvrlst f-cb"]/li[1]/div/a') favourite_url = urls[0].get_attribute("href") except Exception as ex: traceback.print_exc() finally: driver.quit() # print favourite_url return favourite_urlif __name__ == '__main__': for url in ['http://music.163.com/user/home?id=67259702']: # 这里把自己的id替换掉,想爬谁的歌单都可以,只要你有他的id time.sleep(random.randint(2, 4)) # 随机休眠时间2~4秒 url_playlist = catchPlaylist(url) time.sleep(random.randint(1, 2)) catchSongs(url,url_playlist)

    不出意外的话,你的执行脚本的目录下会产生一个以你的id命名的文件,里面打开应该是这样的

    67259702|2|因为了解|None|04:08|汪苏泷|慢慢懂67259702|3|潮鳴り|None|02:37|折戸伸治|CLANNAD ORIGINAL SOUNDTRACK67259702|4|每个人都会|None|02:58|方大同|橙月 Orange Moon67259702|5|Don't Cry (Original)|MV|04:44|Guns N' Roses|Greatest Hits67259702|6|妖孽(Cover:蒋蒋)|None|02:58|醉影An|醉声梦影67259702|7|好好说再见(Cover 陶喆 / 关诗敏)|None|04:06|锦零/疯疯|zero67259702|8|好好说再见(cover陶喆)|None|03:34|AllenRock|WarmCovers ·早# 这边分别爬取的数据结构是: id|歌次序|歌名|是否有MV|时长|歌手|专辑
    Show数据-ROUND1
    接下来就是处理自己下好的自己的歌单了,为了方便起见,我在构造爬取代码的时候,已经构造的比较好了,这也就帮助大家减少了数据预处理的时间了,一般来说,数据不会那么干净的。

    我只是做了最简单的歌手词云的例子,数据比较丰富的情况下,自己处理吧,想做什么统计都可以,或许以后我会补上可视化相关的一些例子
    1. 自定义遮罩层版本# -*- coding: utf-8 -*-# 如果还不清楚词云怎么搞,请参考这里https://mp.weixin.qq.com/s/0Bw8QUo1YfWZR_Boeaxu_Q,或者自行百度,很简单的一个包import numpy as npimport PIL.Image as Imagefrom wordcloud import WordCloud, ImageColorGeneratorimport matplotlib.pyplot as plt# 统计词频# win的用户,把解码去掉即可,因为当时mac写入的文件有编码,所以读出来需要解码def statistics(lst): dic = {} for k in lst: if not k.decode('utf-8') in dic:dic[k.decode('utf-8')] = 0 dic[k.decode('utf-8')] +=1 return dic path = '67259702' # 自己路径自己搞定list_ = []with open(path,'r') as f: for line in f: list_.append(line.strip().split('|')[-2].strip())dict_ = statistics(list_)# the font from github: https://github.com/adobe-fontsfont = r'SimHei.ttf'coloring = np.array(Image.open("screenshot.png")) # 遮罩层自己定义,可选自己的图片wc = WordCloud(background_color="white", collocations=False, font_path=font, width=1400, height=1400, margin=2, mask=np.array(Image.open("screenshot.png"))).generate_from_frequencies(dict_)# 这里采用了generate_from_frequencies(dict_)的方法,里面传入的值是{‘歌手1’:5,‘歌手2’:8,},分别是歌手及出现次数,其实和jieba分词# 之后使用generate(text)是一个效果,只是这里的text已经被jieba封装成字典了image_colors = ImageColorGenerator(np.array(Image.open("screenshot.png")))plt.imshow(wc.recolor(color_func=image_colors))plt.imshow(wc)plt.axis("off")plt.show()wc.to_file('mymusic2.png') # 把词云保存下来

    2. 方块版本# -*- coding: utf-8 -*-# 稍微修改下参数,就是另一幅图,这是没有遮罩层的import numpy as npimport PIL.Image as Imagefrom wordcloud import WordCloud, ImageColorGeneratorimport matplotlib.pyplot as plt# 统计词频def statistics(lst): dic = {} for k in lst: if not k.decode('utf-8') in dic:dic[k.decode('utf-8')] = 0 dic[k.decode('utf-8')] +=1 return dic path = '67259702' # 自己路径自己搞定list_ = []with open(path,'r') as f: for line in f: list_.append(line.strip().split('|')[-2].strip())dict_ = statistics(list_)# the font from github: https://github.com/adobe-fontsfont = r'SimHei.ttf'coloring = np.array(Image.open("screenshot.png"))wc = WordCloud( collocations=False, font_path=font, width=1400, height=1400, margin=2, ).generate_from_frequencies(dict_)# 这里采用了generate_from_frequencies(dict_)的方法,里面传入的值是{‘歌手1’:5,‘歌手2’:8,},分别是歌手及出现次数,其实和jieba分词# 之后使用generate(text)是一个效果,只是这里的text已经被jieba封装成字典了image_colors = ImageColorGenerator(np.array(Image.open("screenshot.png")))plt.imshow(wc)plt.axis("off")plt.show()wc.to_file('mymusic2.png') # 把词云保存下来

    SHOW数据-ROUND2
    刚看到个好玩的,迫不及待的试了下,这是关于语种翻译的API接口,阿里云买的,0.01=1000条,买买买,买来玩玩试试自己歌曲语种

    # -*- coding:utf-8 -*-# 调用的阿里云的API接口实现语种翻译# API官网:https://market.aliyun.com/products/57124001/cmapi010395.html?spm=5176.730005.0.0.UrR9bO#sku=yuncode439500000import urllib, urllib2, sysimport ssldef Lang2Country(text): host = 'https://dm-12.data.aliyun.com' path = '/rest/160601/mt/detect.json' method = 'POST' appcode = 'xxxxx' # 购买后提供的appcode码 querys = '' bodys = {} url = host + path bodys['q'] = text post_data = urllib.urlencode(bodys) request = urllib2.Request(url, post_data) request.add_header('Authorization', 'APPCODE ' + appcode) # 根据API的要求,定义相对应的Content-Type request.add_header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8') ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE response = urllib2.urlopen(request, context=ctx) content = response.read() if (content): # print(content) return content else: return None# 67259702|1|Claux - 水之畔(8lope Remix) (feat. 陶心瑶)|None|02:44|8lope|水之畔(feat. 陶心瑶) (8lope Remix)list_songs = []list_songwithsinger = []with open('67259702') as f: # 文件名写上次爬下来的 for line in f: line_split = line.split('|') list_songs.append(line_split[2]) list_songwithsinger.append(line_split[2]+line_split[5])# 调用接口进行语种识别dict_lang = {}for i in range(537): try: content = Lang2Country(list_songwithsinger[i]) lag_ = json.loads(content)['data']['language'] if lag_ not in dict_lang: dict_lang[lag_]=0 dict_lang[lag_] +=1 except: passprint dict_lang # {u'ru': 1, u'fr': 9, u'en': 111, u'zh': 259, u'pt': 21, u'ko': 8, u'de': 7, u'tr': 15, u'it': 47, u'id': 2, u'pl': 7, u'th': 1, u'nl': 10, u'ja': 17, u'es': 20}

    ok,数据准备好了,接下来可视化就好了!这次我用Echarts,换个口味的就不用云词了,来个统计效果好看点的!


    # 进入该网页:http://echarts.baidu.com/demo.html#pie-simple# 然后把里面的内容替换掉就行option = { title : { text: '哈士奇说喵喜欢的音乐', x:'center' }, tooltip : { trigger: 'item', formatter:'{b} : {c} ({d}%)' }, legend: { orient: 'vertical', left: 'left', data:['中文','英文','俄语','法语','葡萄牙语','韩语','德语','土耳其语','意大利语'] }, series : [ { name: '访问来源', type: 'pie', radius : '55%', center: ['50%', '60%'], itemStyle: { normal: {label:{ show:true, formatter:'{b} : {c} ({d}%)' }, }}, data:[ {value:259, name:'中文'}, {value:111,name:'英文'}, {value:1, name:'俄语'}, {value:9, name:'法语'}, {value:21, name:'葡萄牙语'}, {value:8, name:'韩语'}, {value:7, name:'德语'}, {value:15, name:'土耳其语'}, {value:47, name:'意大利语'}, {value:2, name:'印尼语'}, {value:7, name:'波兰语'}, {value:1, name:'泰语'}, {value:10, name:'荷兰语'}, {value:17, name:'日语'}, {value:20, name:'西班牙语'}, ], } ]};
    Pay Attention
    这里遇到的最大问题,就是网易云的网页竟然还iframe框来做!!!不切入那个内联框架连phantomjs都无能为力!!这是最值得注意的一点,即使你找对了元素,也可能获取不到值!
    如果是win的计算机,在 driver = webdriver.PhantomJS()里面填上phantomjs.exe的路径,上面抓取数据的代码里面有两个需要引擎需要填写路径
    如果有打印出字段,但是记录的数据为0KB,那么是文件没有写进去,对于win的用户,把代码写入的部门,编码方式去掉即可
    有些win的小伙伴反应路径都加载对了,但是还是找不到exe,那么请在路径前面加r比如 executable_path=r"F:\Python\phantomjs-1.9.1-windows\phantomjs.exe"

    结论
    果然一下子就看出是上个世纪九十年代的人(:,还有就是,音乐不分国界,就是动感~

    附录
    对照表

    2 评论 16 下载 2019-04-29 21:42:11 下载需要11点积分
  • 基于OpenCV的批量处理tiff图片黑边(QT环境)

    这几天基础OpenCV,练习写了一个去黑边程序,新手代码,记录一下。
    该方法为扫描线法,遇到非黑边内的(0,0,0)黑色时,用坐标排除(不在边界上跳过)。
    PS:这里还提供一种区域增长思路,找图片黑色区域,面积最大的区域为需要去除的黑边。
    基本思路
    遍历导入图片,遍历像素,找到黑边所在的矩形框坐标,剪切图片(一分为四)
    根据矩形坐标,计算新的地理位置信息
    删除带有黑边的图片和tfw文件信息
    打开和写入保存tif图片和tfw位置信息

    博客链接
    //传入图片 返回图片分割的图片 得到切点坐标QVector<Mat> separationTif(Mat &iplImg, Point2d &cutPnt){ QVector<Mat> vecMat; int width = iplImg.size().width; int height = iplImg.size().height; int begin_wid = 0, end_wid = 0, begin_heig = 0, end_heig = 0; //标记黑边 坐标 int i = 0, j = 0; int blackNumber = 0; for (j = 0; j < height; ++j) { for (i = 0; i < width; ++i) { int tmpb, tmpg, tmpr; tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0]; tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1]; tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2]; if (tmpb == 0 && tmpg == 0 && tmpr == 0) //这里RGB数字可以灵活变动 { ++blackNumber; } } } if (blackNumber == 0) //不存在黑边 { vecMat << iplImg; return vecMat; } else { for (j = 0; j < height; ++j) { bool flag = false; for (i = 0; i < width; ++i) { int tmpb, tmpg, tmpr; tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0]; tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1]; tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2]; if (tmpb == 0 && tmpg == 0 && tmpr == 0) { if (i > 0 && i < width - 1 && j > 0 && j < height - 1) ; else { flag = true; begin_heig = j; break; } } } if (flag) break; } for (j = height - 1; j >= begin_heig; --j) { bool flag = false; //判断 for (i = 0; i < width; ++i) { int tmpb, tmpg, tmpr; tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0]; tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1]; tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2]; if (tmpb == 0 && tmpg == 0 && tmpr == 0) { if (i > 0 && i < width - 1 && j > 0 && j < height - 1) ; else { flag = true; end_heig = j; break; } } } if (flag) break; } for (i = 0; i < width; ++i) { bool flag = false; for (j = 0; j < height; ++j) { int tmpb, tmpg, tmpr; tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0]; tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1]; tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2]; if (tmpb == 0 && tmpg == 0 && tmpr == 0) { if (i > 0 && i < width - 1 && j > 0 && j < height - 1) ; else { flag = true; begin_wid = i; break; } } } if (flag) break; } for (i = width - 1; i >= begin_wid; --i) { bool flag = false; for (j = 0; j < height; ++j) { int tmpb, tmpg, tmpr; tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0]; tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1]; tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2]; if (tmpb == 0 && tmpg == 0 && tmpr == 0) { if (i > 0 && i < width - 1 && j > 0 && j < height - 1) ; else { flag = true; end_wid = i; break; } } } if (flag) break; } if (begin_wid > 0 && begin_wid < (width - 1)) cutPnt.x = begin_wid; else cutPnt.x = end_wid; if (begin_heig > 0 && begin_heig < (height - 1)) cutPnt.y = begin_heig; else cutPnt.y = end_heig; if (cutPnt.x != 0 || cutPnt.y != 0) { //裁剪的中心点不在(0,0)时 剪切图像 cout << "裁剪的中心点为:" << endl; qDebug() << cutPnt.x << cutPnt.y; Mat img0 = Mat(iplImg, Rect(0, 0, cutPnt.x + 1, cutPnt.y + 1)); //左上 Mat img1 = Mat(iplImg, Rect(0, cutPnt.y, cutPnt.x + 1, height - cutPnt.y - 1)); //左下 Mat img2 = Mat(iplImg, Rect(cutPnt.x, 0, width - cutPnt.x - 1, cutPnt.y + 1)); //右上 Mat img3 = Mat(iplImg, Rect(cutPnt.x, cutPnt.y, width - cutPnt.x - 1, height - cutPnt.y - 1)); //右下 vecMat << img0 << img1 << img2 << img3; } else { qDebug() << "Do not have black_border"; vecMat << iplImg; } return vecMat; }}
    0 评论 3 下载 2020-12-03 18:49:03 下载需要8点积分
  • 一键生成QQ个人历史报告

    一、简介近几年,由于微信的流行,大部分人不再频繁使用QQ,所以我们对于自己的QQ数据并不是特别了解。我相信,如果能够生成一份属于自己的QQ历史报告,那将是无比开心的一件事。
    目前网上关于QQ的数据分析工具较少,原因是QQ相关接口比较复杂。而本程序的运行十分简单,具有良好的用户交互界面,只需要扫码登录一步操作即可。
    目前本程序获取的数据包括:QQ详细数据、手机在线时间、非隐身状态下在线时间、QQ活跃时间、单向好友数量、QQ财产分析、群聊分析、过去一年我退出的群聊数据、退去一个月我删除的好友数据、所有代付信息、我最在意的人以及最在意我的人。由于相关的数据接口有访问限制,所以本程序并没有对QQ好友进行分析。
    二、功能截图



    三、如何运行# 跳转到当前目录cd 目录名# 先卸载依赖库pip uninstall -y -r requirement.txt# 再重新安装依赖库pip install -r requirement.txt# 开始运行python main.py
    四、编写思路本程序分为多个模块,模块如下:

    main.py,主程序,用于获取并处理相关数据,并导出数据报告
    qq_bot.py, 核心模块,实现了qq相关的接口,较为复杂
    tkinter_gui.py,绘制gui模块,使用tkinter绘制基本的交互界面
    static_data.py,数据存储模块,所有数据采用base64编码存储

    4.1 main.py模块首先,初始化相关文件夹,并调用qq_bot.py模块,定义一个qq bot对象,该对象为本程序的核心对象,所有数据获取均从该对象获取。
    同时,本程序数据的报告文件为.md格式
    # 初始化文件夹 init_folders() # 写入项目所需资源文件到本地目录 write_data() # 创建一个自己编写的qq bot对象 bot = Bot() custom_print(u'登录成功,正在获取数据...') # 定义欲输出的markdown字符串 markdown_content = ''' <p align="center"> <font size='6px'>{qq_number}的个人QQ历史报告</font> <img src="{qq_icon_png}" align="right" height="60"> </p> ''' # 更新一下欲输出的markdown文本 markdown_content = markdown_content.replace('{qq_number}',bot.qq_number) markdown_content = markdown_content.replace('{qq_icon_png}', 'data/qq_icon.png')
    登录成功后,开始获取该登录账户的详细资料
    custom_print(u'正在获取该登录账户的详细数据...') detail_information = bot.get_detail_information() # content为markdown语法文本 content = '\n<br/><br/>\n' + '## 我的详细资料\n' + '种类|内容\n:- | :-\n' for key, value in detail_information.items(): if key == 'qq_level': star_count, moon_count, sun_count, crown_count = calculate_level(value) data = crown_count * '![](data/level_crown.png)' + sun_count * '![](data/level_sun.png)' + moon_count * '![](data/level_moon.png)' + star_count * '![](data/level_star.png)' content += '{}|{}\n'.format(key_dict[key], data) else: content += '{}|{}\n'.format(key_dict[key], value) # 更新一下欲输出的markdown文本 markdown_content += content markdown_content += '\n> 注:单向好友表示他/她的列表中有你,而你的列表中没有他/她' # 每个步骤完成后,保存markdown文件,以便防止程序出错时能够保存到最新的数据 with open('{}的个人QQ历史报告.md'.format(bot.qq_number), 'w', encoding='utf-8') as file: file.write(markdown_content)
    接着,获取所有qq好友的备注名和qq号
    all_qq_friends = bot.get_all_friends_in_qq() custom_print(u'所有qq好友号码和备注名中...') qq_number_list = [] for key, friend_group in all_qq_friends.items(): for info in friend_group['mems']: qq_number_list.append(info['uin'])
    并获取所有群数据
    # 获取所有群信息 custom_print(u'获取该QQ加入的所有群信息...') group_list = bot.get_group() print(group_list) # content为markdown语法文本 content = '\n\n<br/><br/>\n' + '## 我加入的群资料\n' + '序号|群名|群号|群主QQ\n:- | :-| :-| :-\n' # 获取某个群的群成员信息 for index, group in enumerate(group_list): group_number = group['gc'] group_name = group['gn'] owner = group['owner'] content += '{}|{}|{}|{}\n'.format(str(index+1), str(group_name), str(group_number), str(owner)) # 更新一下欲输出的markdown文本 markdown_content += content # 每个步骤完成后,保存markdown文件,以便防止程序出错时能够保存到最新的数据 with open('{}的个人QQ历史报告.md'.format(bot.qq_number), 'w', encoding='utf-8') as file: file.write(markdown_content)
    接下来的步骤如你所需,也就是获取其他相关的数据,所以本小节就不一一详细解释了,您可以查看相关源代码查看。获取的数据包括:

    获取过去30天内退出的群名单
    获取过去364天内删除的好友名单
    判断此次登录的qq是否为vip或者svip
    获取qb值
    获取代付信息
    亲密度排行榜
    共同好友数
    成为好友的天数

    4.2 qq_bot模块此模块实现了获取qq数据的接口,主要通过抓包获得数据、分析数据,对参数进行加密解密等。
    首先,是模拟扫码登录id.qq.com,qun.qq.com,qzone.qq.com。三者登录方式大同小异,唯一有区别的就是提交数据中的参数加密方式不同。
    我们以id.qq.com登录为例:
    def login_id_qq_com(self): # 登录id.qq.com # 访问网页,为了获取参数pt_login_sig login_url = 'https://xui.ptlogin2.qq.com/cgi-bin/xlogin?pt_disable_pwd=1&appid=1006102&daid=1&style=23&hide_border=1&proxy_url=https://id.qq.com/login/proxy.html&s_url=https://id.qq.com/index.html' html = get_html(login_url, '') # 对返回的cookies进行转化为dict类型,方便处理 cookies_back_dict = dict_from_cookiejar(html.cookies) pt_login_sig = cookies_back_dict['pt_login_sig'] self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict) # 访问网页,为了获取参数ptqrtoken qrcode_url = 'https://ssl.ptlogin2.qq.com/ptqrshow?appid=1006102&e=2&l=M&s=4&d=72&v=4&t=0.10239549811477189&daid=1&pt_3rd_aid=0' html = get_html(qrcode_url, '') # 对返回的cookies进行转化为dict类型,方便处理 cookies_back_dict = dict_from_cookiejar(html.cookies) qrsig = cookies_back_dict['qrsig'] ptqrtoken = hash33_token(qrsig) self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict) # 将二维码显示到图片框 BytesIOObj = BytesIO() BytesIOObj.write(html.content) qr_code = PIL.Image.open(BytesIOObj) image = PIL.ImageTk.PhotoImage(qr_code) image_label['image'] = image # 实时检测二维码状态 while (True): # 目标网址 target_url = 'https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://id.qq.com/index.html&ptqrtoken=' + str(ptqrtoken) + '&ptredirect=1&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1556812236254&js_ver=19042519&js_type=1&login_sig=' + str(pt_login_sig) + '&pt_uistyle=40&aid=1006102&daid=1&' # 登录,需要带上访问cookies html = get_html(target_url, self.cookies_merge_dict_in_id_qq_com) # 返回的响应码为200说明二维码没过期 if (html.status_code): if ('二维码未失效' in html.text): custom_print(u'(1/3)登录id.qq.com中,当前二维码未失效,请你扫描二维码进行登录') elif ('二维码认证' in html.text): custom_print(u'(1/3)登录id.qq.com中,扫描成功,正在认证中') elif ('登录成功' in html.text): self.is_login = True custom_print(u'(1/3)登录id.qq.com中,登录成功') break if ('二维码已经失效' in html.text): custom_print(u'(1/3)登录id.qq.com中,当前二维码已失效,请重启本软件') exit() # 延时 time.sleep(2) # 登录成功后,把返回的cookies合并进去 self.cookies_merge_dict_in_id_qq_com = dict_from_cookiejar(html.cookies) self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict) # print(u'当前cookies:{}'.format(cookies_merge_dict)) # 获取此次登录的qq号码 qq_list = re.findall(r'&uin=(.+?)&service', html.text) self.qq_number = qq_list[0] # 登录成功后,会返回一个地址,需要对该地址进行访问以便获取新的返回cookies startIndex = (html.text).find('http') endIndex = (html.text).find('pt_3rd_aid=0') url = (html.text)[startIndex:endIndex] + 'pt_3rd_aid=0' # 屏蔽https证书警告 urllib3.disable_warnings() # 这里需要注意的是,需要禁止重定向,才能正确获得返回的cookies html = get(url, cookies=self.cookies_merge_dict_in_id_qq_com, allow_redirects=False, verify=False) # 把返回的cookies合并进去 cookies_back_dict = dict_from_cookiejar(html.cookies) self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict)
    首先是访问指定网址,获取参数pt_login_sig,其次是访问另外一个网址,获取参数qrsig,通过加密函数,将参数qrsig转化为ptqrtoken,然后就是获取二维码图片的状态了。当我们检测到登录成功时,就证明用户已经完成扫码操作,此时将网址返回的cookie保存下来。
    这里要说明的是,加密函数的获取,需要具备一定的抓包基础才能获取得到。本程序的几个加密函数如下:
    # 对qrsig进行基本的加密,该加密函数由抓包获得,需要具备一定抓包知识才能找到该加密函数# 根据javascript版的加密函数,将其改写成python版本def hash33_token(t): e, n = 0, len(t) for i in range(0,n): e += (e << 5) + ord(t[i]) return 2147483647 & e# 对skey进行基本的加密,该加密函数由抓包获得,需要具备一定抓包知识才能找到该加密函数# 根据javascript版的加密函数,将其改写成python版本def hash33_bkn(skey): e = skey t = 5381 for n in range(0,len(e)): t += (t << 5) + ord(e[n]) return 2147483647 & t
    由于该模块下具有许多获取相关数据的qq接口,但是它们的形式非常相似,所以本节仅仅以获取所有qq群数据为例:
    def get_group(self): # 获取所有群基本信息 # bkn由参数skey通过另一个加密函数得到 bkn = hash33_bkn(self.cookies_merge_dict_in_qun_qq_com['skey']) submit_data = {'bkn': bkn} html = post_html('https://qun.qq.com/cgi-bin/qun_mgr/get_group_list', self.cookies_merge_dict_in_qun_qq_com, submit_data) group_info = loads(html.text) print(group_info) return group_info['join']
    这里主要涉及到的还是参数的加密、解密过程,这是一个难点,其他的话还是比较简单的。
    4.3 tkinter_gui模块这个模块是绘制基本的gui模块,采用python内置的tkinter模块完成,用法相当简单,这里就不详细讲了。
    4.4 static_data模块这个模块主要是用来存储相关的数据的,在程序每次运行时,将该静态资源文件输出。这么做的原因是可以防止用户将某些静态数据给删除了,导致程序运行错误。
    五、补充完整版源代码存放在github上,有需要的可以下载
    项目持续更新,欢迎您star本项目
    LicenseThe MIT License (MIT)
    3 评论 3 下载 2020-10-27 12:56:14 下载需要8点积分
  • 基于Python实现的抓包分析软件

    一、简介这是一个学习模仿WireShark的抓包软件。可以的功能有:侦听、解析、构造数据包等。其中还包括扩展功能:流量监测和攻击检测(Land攻击,Ping of Death)。软件目前支持解析:IP、IPv6、ARP、TCP、UDP、ICMP、ICMPv6、SSDP、HTTP、TLS。
    二、主要功能
    侦听指定网卡或所有网卡,抓取流经网卡的数据包
    解析捕获的数据包每层的每个字段,查看数据包的详细内容
    可通过不同的需求设置了BPF过滤器,获取指定地址、端口或协议等相关条件的报文
    针对应用进行流量监测,监测结果实时在流量图显示,并可设置流量预警线,当流量超过预警线时自动报警
    提供了以饼状图的形式统计ARP、TCP、UDP、ICMP报文,以柱状图的形式统计IPv4、IPv6报文
    可将抓取到的数据包另存为pcap文件,并能通过打开一个pcap文件对其中的数据包进行解析
    可逐层逐字段构造数据包,实现自定义数据包发送

    三、主要模块
    数据报文采集模块:完成网络接口数据的捕获、解析,可以根据用户定义条件组合来进行捕获,如只监视采用TCP或UDP协议的数据包,也可以监视用户希望关注的相关IP地址的数据包,同时完成数据封包日志记录,提高了系统的灵活性。此外,对IP类型、ARP、TCP、UDP、ICMP的数量进行统计。
    应用流量监测模块:获取当前正在运行的应用进程,用户可选择一个应用进行流量监测,获取应用中流量信息,同时对一些常见的入侵攻击特征进行判断,如根据源目的地址是否相同判断Land攻击、IP头部长度是否过长判断ping拒绝服务攻击,并发出预警。
    报文伪造模块:可以自行构造Ether、IP、TCP、UDP、ICMP、ARP报文,并选择send()、sendp()、sr()、srl()、srloop()五种方式发送报文以实现简单攻击或对TCP/IP进行调试。
    界面显示模块:设计系统主窗口即数据报文采集界面、应用流量监测界面、报文伪造界面。并完成报文统计图的显示,流量图的显示。
    四、源代码结构
    img存放程序中使用的背景和图标。
    capture_core.py抓包程序的后台文件,主要用来生成数据包的摘要信息、分析数据包的结构、程序状态处理、下载速度和上传速度的更新等。
    flow_monitor.py流量监控程序的后台服务代码,实时更新速度、应用流量的过滤及摘要信息的生成、更新应用的网络连接等。
    forged_packet用于构造数据包并发送,可自定义数据包的每个字段,实现网络攻击或网络欺骗等功能。
    main_ui.py抓包程序的GUI代码,包括了快捷键的绑定以及可自定义字体和背景图片、已抓到数据包的摘要信息的展示、显示某个数据包的详细信息和十六进制数据等功能。
    main.py程序的入口。
    monitor_system.py流量监控的GUI代码,用于查看网络连接速度等。
    tools.py工具代码,用于获取网卡的NIC、格式的转换、网络连接速度的获取。
    data.json用于存放程序的配置信息。

    五、环境依赖
    Python 3.6
    Scapy 2.4

    Linux & Windows
    # pip install psutil scapy matplotlib pyqt5
    在Windows下,还需要
    # pip install wmi pywin32
    六、使用方法进入项目目录
    # cd WireWhale # python main.py
    七、部分功能介绍
    主界面主要包括5个部分:
    菜单栏
    文件:文件保存、打开,软件退出编辑:可自行设置主窗体字体捕获:捕获数据包的流程分析:两大拓展功能,应用流量监测和伪造数据包统计:报文统计帮助:功能介绍及版权声明
    工具栏
    界面初始时,根据程序运行状态转移图只有开始键可以响应设置了标志位:start_flag、pause_flag、stop_flag、save_flag,用于对程序中一些函数的使用添加限制。开始、暂停、停止、重新开始四个按钮全部按照下图逻辑设置在什么情况下可响应下面为部分状态截图
    起始状态运行状态暂停状态停止状态

    过滤器以及网卡选择
    页面初始化时网卡选择下拉框获取网卡信息进行显示,如下图所示,默认全选
    报文显示
    根据报文类型显示不同颜色,以进行明显的区别报文解析以树状结构显示,层次结构清晰明了抓包简略信息显示框定时滑到最底部
    状态栏(显示当前网卡、实时收发包速度、上传下载速度)

    数据统计模块:绘制图使用python下最流行的数据处理框架Matplotlib绘制要求的统计图。


    八、软件运行时部分截图8.1 主程序



    8.2 数据包伪造

    8.3 流量监控
    2 评论 48 下载 2019-05-17 17:03:33 下载需要12点积分
  • 基于Python的有道翻译小软件


    Python 2.7.13
    IDE Pycharm 5.0.3
    macOS 10.12.1

    前言
    花了一点时间,半抄半写半修改的写了第一个能用的python小程序,作用是在IDE端模拟有道词典的访问,效果如下图所示,不足之处在于,当输入的中英文字符串超过一定数量,会抛出中间代码,新手并不知道怎么处理,望知道的不吝赐教

    初阶:交互界面
    首先在jupyter或者pycharm中进行交互的操作,核心语句是使用raw_input捕获系统输入

    1. 效果图
    2. 代码# -*- coding: utf-8 -*-import urllib2import urllib # python2.7才需要两个urllibimport jsonwhile True: content = raw_input("请输入需要翻译的内容:") # 系统捕获输入,就是命令框会弹出提示,需要你进行手动输入 if content == 'q': # 输入q退出while循环 break url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=null" data = {} # 构造data,里面构造参数传入 data['type'] = 'AUTO' data['i']=content data['doctype'] = 'json' data['xmlVersion'] = '1.8' data['keyfrom'] = 'fanyi.web' data['ue'] = 'UTF-8' data['action'] = 'FY_BY_ENTER' data['typoResult'] = 'true' data = urllib.urlencode(data).encode('utf-8') # 将构造的data编码 req = urllib2.Request(url) # 向浏览器发出请求 response = urllib2.urlopen(req, data) # 带参请求,返回执行结果 html = response.read().decode('utf-8') # print(html) # 可以取消print的注释,查看其中效果,这边获取的结果是进行解析 target = json.loads(html) # 以json形式载入获取到的html字符串 print "翻译的内容是:"+target['translateResult'][0][0]['tgt'].encode('utf-8')# 请输入需要翻译的内容:test# 翻译的内容是:测试# 请输入需要翻译的内容:测试# 翻译的内容是:test# 请输入需要翻译的内容:q
    注意:这里的data字典中的数据根据实际网页中数据为准,可能会不一样,具体操作,点击审查元素。
    进阶:做成gui
    离实用还差那么两步,第一步是先做成GUI

    1. 界面效果
    2. 代码# -*- coding: utf-8 -*-from Tkinter import *import difflibimport urllib2import urllib # python2.7才需要两个urllibimport json# ----------------------主框架部分----------------------root = Tk()root.title('翻译GUI&beta1')root.geometry()Label_root=Label(root)#-----------------------定义规则------------------------def translate(content): url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=null" data = {} # 构造data,里面构造参数传入 data['type'] = 'AUTO' data['i']=content data['doctype'] = 'json' data['xmlVersion'] = '1.8' data['keyfrom'] = 'fanyi.web' data['ue'] = 'UTF-8' data['action'] = 'FY_BY_ENTER' data['typoResult'] = 'true' data = urllib.urlencode(data).encode('utf-8') # 将构造的data编码 req = urllib2.Request(url) # 向浏览器发出请求 response = urllib2.urlopen(req, data) # 带参请求,返回执行结果 html = response.read().decode('utf-8') # print(html) # 可以取消print的注释,查看其中效果,这边获取的结果是进行解析 target = json.loads(html) # 以json形式载入获取到的html字符串 #print u"翻译的内容是:"+target['translateResult'][0][0]['tgt'] return target['translateResult'][0][0]['tgt'].encode('utf-8')#还可以继续增加规则函数,只要是两输入的参数都可以#----------------------触发函数-----------------------def Answ():# 规则函数 Ans.insert(END,"翻译 %s: "%var_first.get().encode('utf-8') + translate(var_first.get().encode('utf-8')))def Clea():#清空函数 input_num_first.delete(0,END)#这里entry的delect用0 Ans.delete(0,END)#text中的用0.0#----------------------输入选择框架--------------------frame_input = Frame(root)Label_input=Label(frame_input, text='请输入需要翻译的内容', font=('',15))var_first = StringVar()input_num_first = Entry(frame_input, textvariable=var_first)#---------------------计算结果框架---------------------frame_output = Frame(root)Label_output=Label(frame_output, font=('',15))Ans = Listbox(frame_output, height=5,width=30) #text也可以,Listbox好处在于换行#-----------------------Button-----------------------calc = Button(frame_output,text='翻译', command=Answ)cle = Button(frame_output,text='清空', command=Clea)Label_root.pack(side=TOP)frame_input.pack(side=TOP)Label_input.pack(side=LEFT)input_num_first.pack(side=LEFT)frame_output.pack(side=TOP)Label_output.pack(side=LEFT)calc.pack(side=LEFT)cle.pack(side=LEFT)Ans.pack(side=LEFT)#-------------------root.mainloop()------------------root.mainloop()
    高阶:发布应用
    如何在小伙伴面前装B才是我学习的动力,哈哈哈

    Pay Attention
    python3的用户注意url包的使用和python2是有区别的,请根据实际需求自行百度
    Python如果操作频率太快或者网页限制机器人对此的访问,则需要修改head了,修改代码后.当然每个电脑的user都不一样,具体去审查元素查看。

    req = urllib2.Request(url) # 生成对象# 添加如下一行代码;req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36'),这样就可以伪装成人类啦
    当然也可以添加延时模块, 即可限定访问时间。
    import time #添加延时模块time.sleep(1)#休息1秒钟再进行操作
    python3的同学需要Tkinter改成小写,还有就是注意编码部分的转化。
    mac的同学可能遇到tkinter无法输入中文问题,可能是由tkinter版本过低导致,解决方案参考:MAC 系统中,Tkinter 无法用 中文输入法 输入中文
    3 评论 8 下载 2019-05-02 20:42:33 下载需要11点积分
  • 基于PyQT5、PocketSphinx的python语音识别小程序

    1.使用说明1.1 项目简介参照微软cotana的工作方式,编写自己的一个python语音助手程序,借助PyQt5和Pipy,创建可视化窗口,能实现基本的语音识别功能,同时根据几个特定的关键词执行简单的行动(如music,readme等)。
    1.2 项目功能要求
    实现语音识别,并将识别的内容在屏幕上打印出来
    设置几个命令关键词(music,readme),并实现相应的行动。若识别出的内容中包含设置的几个关键词,则程序执行相应的行动。
    设置两种识别模式:PocketSphinx中包含7个Recognizer API:程序中使用了两个API:recognize_sphinx和recognize_google。(两种识别模式可由用户自行选择,其中recognize_sphinx可直接在本地运行,但识别精度较低;recognize_google识别精度较高,但是使用recognize_google需要处于联网状态下且IP地址需要在境外,否则语音识别会出现错误)
    设置文本框:用户可直接在文本框中输入命令,其执行效力与语音输入等效

    2.程序设计与实现2.1 设计class Ui_MainWindow(object):
    Ui_Mainwindow类加载图形化用户界面,控制界面布局,类中包含各种Label,PushButton,MenuBar控件。
    class myWindow(QtWidgets.QMainWindow):
    mywindow类处理交互逻辑,类中包含各种执行函数,同时实现控件与函数的连接。
    2.2 主要函数实现声音监听与处理函数def listen(self): # Working with Microphones mic = sr.Recognizer() with sr.Microphone() as source: # use the default microphone as the audio source audio = mic.listen(source) # listen for the first phrase and extract it into audio data try: if self.isgoogle: content = mic.recognize_google(audio) else: content = mic.recognize_sphinx(audio) except sr.RequestError: self.ui.label.setText("Something was wrong! Try again......") COMMEND = ["music", "open"] commend_is_music = re.search(COMMEND[0].lower(), content.lower()) commend_is_file = re.search(COMMEND[1].lower(), content.lower()) if commend_is_music: self.ui.label.setText("you said: \" " + content + "\"") win32api.ShellExecute(0, 'open', 'D:\\网易云音乐\\CloudMusic\\cloudmusic.exe', '', '', 1) elif commend_is_file: self.ui.label.setText("you said: \"" + content + "\"") win32api.ShellExecute(0, 'open', 'D:\\Notpad++\\Notepad++\\notepad++.exe', '', '', 0) else: self.ui.label.setText("you said: \" " + content + "\"\nIt's not a valid command.")
    创建监听线程def listen_thread(self): self.ui.label.setText("I'm listening...... ") t1 = threading.Thread(target=self.listen) t1.setDaemon(True) t1.start()
    文本处理函数def text_changed(self): content = self.ui.textbox.text() print(content) COMMEND = ["music", "open"] commend_is_music = re.search(COMMEND[0].lower(), content.lower()) commend_is_file = re.search(COMMEND[1].lower(), content.lower()) if commend_is_music: self.ui.label.setText("you typed: \" " + content + "\"") win32api.ShellExecute(0, 'open', 'D:\\网易云音乐\\CloudMusic\\cloudmusic.exe', '', '', 1) elif commend_is_file: self.ui.label.setText("you typed: \"" + content + "\"") win32api.ShellExecute(0, 'open', 'D:\\Notpad++\\Notepad++\\notepad++.exe', '', '', 0) else: self.ui.label.setText("you typed: \" " + content + "\"\nIt's not a valid command.")
    创建文本处理线程def text_thread(self): t2 = threading.Thread(target=self.text_changed) t2.setDaemon(True) t2.start()
    连接各类控件与相应函数self.ui.recognize_btn.clicked.connect(self.listen_thread)#语音识别按钮连接监听线程self.ui.sphinx_bar.triggered.connect(self.sphinxbar_recognize)#sphinx模式触发self.ui.google_bar.triggered.connect(self.googlebar_recognize)#google模式触发self.ui.text_btn.clicked.connect(self.text_thread)#文本框输入确认按钮连接文本处理线程
    3.测试截图


    5 评论 21 下载 2019-05-11 23:24:40 下载需要11点积分
  • 基于Qt实现的AI同化棋游戏

    这是一个非常简单的 AI,基于这个框架,还可以进行大量改进以提高智商,代码已经进行了很基础的封装,关键过程的说明见注释。
    以下可参考:

    https://en.wikipedia.org/wiki/Minimax
    https://cs.uwaterloo.ca/~cbright/reports/cs686project.pdf ,(Negamax 是 miniMax 的变体)

    Minimax 算法首先,同化棋是一种“0和”对抗游戏(一方优势一方必然劣势) 那么我们考虑用通过 Minimax 算法解决。
    Minimax 算法又名极小化极大算法,是一种找出失败的最大可能性中的最小值的算法。
    简单来说,就是枚举当前执行者所有可能的选择,不断一层层拓展局面,达到限定层数后,对局面进行估值,然后按 MAX 层选择分支的最大值,MIN 层选择分支的最小值,模拟对弈双方的选择。
    α-β剪枝通过分析可以发现,在利用穷举方法执行 Minimax 算法中有许多的无效搜索,也就是说,许多明显较劣的状态分支我们也进行搜索了。
    我们在进行极大值搜索的时候,我们仅仅关心,下面最大的状态,对于任何小于目前值的分支也都是完全没有必要进行进一步检查的。

    图中 MIN 层第二个结点,在得到下一层的估值 2 后,它的返回值必然<=2,而上一层是 MAX 层,从 MIN 层第一个结点已经得到了 4,故其>=4,所以,MIN 层第二个结点必然不会被选 择,没有继续的必要。
    同理,我们在进行极小值搜索的时候,我们仅仅关心,下面最小的状态,对于任何大于目前值的分支都是完全没有必要进行进一步检查的。

    估价函数使用 Minimax 算法,最为关键的部分是如何对一个局面进行估价,判断其到底有多大的可能性会给 AI 带来胜利。
    分析同化棋的规则,容易发现其局面上的总棋子数是不减的。那么,双方获得的棋子的差是最容易想到的估价,也是此 AI 所使用的主要估价。
    其次,经过尝试,当一方占据半壁江山(>24)后,非常容易走向胜利,所以我们贪心地尽量让其超过一半,即给予较高估价。
    改进此 AI 可以进一步改进的地方:
    1.估价函数由于同化棋一步可以最多同化 8 个棋子,所以可能当前你优势(棋子差额)很大,但是下一步立马被翻盘。所以我们可以考虑统计一些容易被同化的如中空的方形,菱形的个数,给予估价值。还有很多估值方法…
    2.优化程序以加速根据 Minimax 算法的特点,在时限内搜索的层数越深,结点越多,选择就越优,AI 的智商就越高。此 AI 以易读性为主,牺牲了许多性能,可以做许多改进:
    (1)状态压缩对于一个棋盘,由于其只有 49 个位置,我们可以把位置映射到 0~48 这 49 个数 (f(x,y) = x * 7 + y) ,对于某个位置,其只有存在棋子,不存在棋子,两种状态,所以对于对弈的一方,我们可以用一个 64 位整数的第 k 个 2 进制位=0/1 表示是否在 k 位置有这个数,从而把他的所有棋子的位置映射成一个 64 位整数(c++: long long int)。
    这样一来,棋盘状态由一个 7*7 数组变成了两个整数,我们可以使用位运算,十分快速地进行查找位置,更新状态,统计个数等等操作。将压缩的状态 hash 判断冲突是防止进入循环局面的方法之一。
    (2)剪枝及搜索顺序如已经被已方及边界与最近对方分隔 2 层以上的己方完全占领区域的棋子,是可以稍后考虑的。 接近对方边缘部位的棋子是可以优先考虑的,这样可以容易得出接近最优值的选择,更高效地利用α-β剪枝。
    (3)常数优化根据语言及计算机的一些特性,在不改变功能的情况下对程序的语句进行修改,以期获得更好的性能。
    3. 随机化可以用随机化在一定程度上防止局面陷入循环,或者被对手用同样的走法再次打败。但要注意,不能随机进入一个劣势局面。
    4.迭代加深因为此 AI 现有估价及搜法较弱,最大搜索层数很低,所以在搜索时采用迭代加深层数限制的方法,这就产生了问题,下一个深度是沿用之前所有搜索深度得到的首层 max、min 值(通常在低深度得到最优值), 还是初始化 max,min 值,现版本 AI 经测试,第一种占优,但是改进后,是否还进行迭代加深,或者采取哪种方法,需测试。(理论上第二种占优,本质上第一种是贪心)。
    界面展示人人对弈,搜索深度为3

    AI先手,搜索深度为3

    AI后手,搜索深度为5
    1 评论 10 下载 2020-06-26 12:03:03 下载需要12点积分
  • 基于WIN32 API实现黄金矿工游戏单人版

    一、什么是设计文档游戏类型是什么?游戏有哪些功能?相关数学公式是什么?
    描述一个游戏的所有功能,这就是设计文档,也叫需求说明。真正的设计文档,并不是我写的这个样子,应该由策划来写(俗称“案子”)。我写的这篇,有流程图、有分类,条理清晰,基本上和真实代码完全对应,已经接近伪码了。
    二、游戏状态图
    三、游戏功能设计1.开屏

    显示内容:
    程序启动后,显示初始化图片,计时结束,进入菜单界面。
    逻辑处理:
    控制图片从左至右显示。

    2.菜单

    显示内容:
    显示菜单背景图片,显示“开始”按钮。
    逻辑处理:
    检测鼠标移动。当鼠标移动到按钮上,更改按钮图片。
    检测鼠标单击。当按下按钮后,初始化游戏数据,开始“地图加载”动画。

    3. 地图加载动画

    显示内容:
    显示背景图片,进度条,显示当前关卡、目标金钱数量。
    逻辑处理:
    控制进度条移动。

    4. 游戏中

    显示内容:
    显示人物图片,地面背景。
    显示当前金钱数量,目标金钱数量,剩余时间。
    显示叉子。
    显示金子、石头。
    显示炮的数量。
    显示爆炸动画。
    逻辑处理:
    控制叉子摆动,伸出,收回。
    检测按键“下”,按下后,叉子伸出。
    检测叉子是否碰到物品,碰到物品后,叉子收回,物品跟随叉子移动。
    当物品移动到地面位置,清除物品,增加金钱。
    胜负判断。
    道具使用:
    检测按键“上”,按下后,清除当前所抓物品,播放爆炸动画。
    判断玩家属性:如果有“体力”道具,增加叉子收回速度。
    判断玩家属性:如果有“魔法”道具,增加物品价值。

    5.游戏过关

    显示内容:
    显示过关图片。
    逻辑处理:
    计时结束,进入“购买道具”状态。

    6.购买道具

    显示内容:
    道具按钮:炮,体力,魔法。
    “下一关”按钮。
    逻辑处理:
    检测鼠标移动。当鼠标移动到按钮上,更改按钮图片。
    点击“炮”,增加炮的数量。
    点击“体力”,增加叉子收回速度。
    点击“魔法”,设置玩家属性:有魔法道具。
    点击“下一关”,加载地图,进入下一关游戏。

    7.游戏失败

    显示内容:
    显示失败图片。
    逻辑处理:
    计时结束,进入“菜单”状态。

    8.游戏通关

    显示内容:
    显示通关图片。
    逻辑处理:
    计时结束,进入“菜单”状态。

    四、叉子坐标系统叉子所在位置为坐标原点,所在位置垂线为X轴。向左摆动,旋转角度A大于0;向右摆动,旋转角度A小于0。其中,x,y是屏幕坐标系统。叉子坐标系统示意图:

    五、碰撞检测怎样检测叉子碰到了物品?在叉子端口处,设定一个圆形区域。如果这个圆与物品碰撞,则叉子碰到了物品。示意图如下:

    其中,圆心坐标A(50, 0) ,半径14。
    物品的检测范围也是圆形区域,示意图如下:

    六、地图数据物品属性表



    ID
    价值
    名称
    检测半径(像素)
    移动速度(像素)




    0
    500
    金子
    32
    4


    1
    150
    金子
    24
    12


    2
    50
    金子
    16
    20


    3
    15
    石头
    24
    12


    4
    5
    石头
    16
    20


    5
    600
    钻石
    16
    20



    地图物品数据
    目前只制作了3张地图。
    第一关地图,过关金钱数量:700



    ID
    横坐标
    纵坐标




    0
    50
    110


    1
    100
    270


    2
    200
    370


    1
    380
    370


    2
    480
    340


    0
    550
    150


    3
    190
    190


    4
    390
    260


    5
    120
    380



    第二关,过关金钱数量:1000



    ID
    横坐标
    纵坐标




    1
    50
    110


    4
    100
    270


    2
    200
    370


    3
    380
    370


    4
    480
    340


    5
    450
    400


    0
    550
    150


    1
    190
    190


    2
    390
    260



    第三关,过关金钱数量:2000



    ID
    横坐标
    纵坐标




    4
    50
    110


    1
    100
    270


    0
    200
    370


    0
    380
    370


    3
    480
    340


    4
    550
    150


    2
    190
    190


    4
    390
    260


    5
    460
    300



    游戏截图

    4 评论 137 下载 2018-10-04 21:41:13 下载需要15点积分
  • 基于python的自动续借图书集


    Python 2.7
    IDE Pycharm 5.0.3
    Firefox浏览器:47.0.1

    目的自动实现图书馆借书籍的书单截图,并一键续约全部书籍,我登录校图书馆的目的无非就这两个咯,我才不去预约没有的书呢—反正没有一次预约成功过0.0
    实现方法Selenium+PhantonJS自动化脚本执行
    实现方案
    采用Firefox浏览器进行模拟登录,这个比较酷炫把,可以看着浏览器自己在那边跑,欢快的停不下来。。。
    调用PhantomJS.exe,不展现浏览器的运作,直接在cmd窗口跑(用pyinstaller打包成exe后有cmd窗)

    方案实现过程采用Selenium+Firefox方式:
    先来个最后成品动图:

    然后来程序代码—主模块(被调用模块,也可单独执行)
    # -*- coding: utf-8 -*-from selenium import webdriverimport time#shift-tab多行缩进(左)print 'please wait...system loading...'#reload(sys)PostUrl = "http://lib.hrbeu.edu.cn/#"driver=webdriver.Firefox()#用浏览器实现访问#driver = webdriver.PhantomJS(executable_path="phantomjs.exe")#没用浏览器driver.get(PostUrl)elem_user = driver.find_element_by_name('number')elem_psw = driver.find_element_by_name('passwd')#选择我的图书馆,点击后才能看到输入账号密码click_first = driver.find_element_by_xpath("//ul[@id='imgmenu']/li[4]")click_first.click()elem_user.send_keys('S315080092')elem_psw.send_keys('xxxxxxxxx')#点击登录click_second = driver.find_element_by_name('submit')click_second.click()print 'log in...'time.sleep(1)#定位新页面元素,将handle重定位即可driver.switch_to_window(driver.window_handles[1])#定位弹出的第一个页面,也就是当前页面#sreach_window = driver.current_window_handle #此行代码用来定位当前页面#不可行driver.find_element_by_xpath("/html/body/div[4]/div/div/ul/li[3]/a").click()driver.save_screenshot('image_booklist_firefox.jpg')print 'turning to the mylib...'time.sleep(1)#搜索结果页面停留片刻#driver.switch_to_window(driver.window_handles[1])#没有跳出新窗口就是在同一页面的!for i in range(2,30):#这里限定是29本书,一般我们都不会借那么多书的 try: #driver.find_element_by_xpath("/html/body/div[4]/div/div[2]/table/tbody/%s/td[8]/div/input"%('tr[%s]'%i)).click()#下面的比较好理解 driver.find_element_by_xpath("/html/body/div[4]/div/div[2]/table/tbody/tr[%s]/td[8]/div/input"%i).click() print 'renewing...the %d\'th book renewed '%(i-1) except: print '%d books have been renewed !'%(i-2) a=i-2 time.sleep(4) driver.save_screenshot('image_done_firefox.jpg') print 'the picture is saving...' print 'done!' breaktime.sleep(1)driver.close()driver.quit()
    调用上述模块的主执行函数(其实就是为了封装上述模块而已,封装成gui界面,为后续的打包做准备)
    # -*- coding: utf-8 -*-from Tkinter import *import tkMessageBox#执行gui窗import timedef check_renew(): print 'checking and renewing...' tkMessageBox.showinfo('提示','即将开启装逼模式,请确认已安装Firefox浏览器') #time.sleep(4) import Selenium_PhantomJS_lib_firefox tkMessageBox.showinfo('提示','已执行成功!\n(截图已保存于程序目录)')#主框架部分root = Tk()root.title('图书馆查询续约(哈尔滨工程大学专版))label=Label(root,text=' 图书馆一键查询与续约Firefox版本 (✪ω✪) ')button_check=Button(root,text='查询书单并续期━Σ(゚Д゚|||)━开启Firefox有形装逼模式 ',background='green',command=check_renew)label.pack()button_check.pack()root.mainloop()
    实现效果如图所示:

    程序中的注释相信可以把程序解释的差不多了把。。。。
    遇到问题和解决方案
    selenium对新页面元素无法定位抛出NoSuchElementException: Message: Unable to locate element
    错误,导致无法进行对新的界面进行点击操作。
    解决方案:专门写了一篇博客,请见
    解决Selenium弹出新页面无法定位元素问题(Unable to locate element)

    对打包后的版本无法运行,抛出如图错误Errno 10054

    解决方案:暂未找到解决方案,exe文件不可用,程序执行可用

    对未知书籍数目重复点击操作,代码冗余
    解决方案:因为点击续借按钮的元素每个都不一样,通过观察可知其中的规律,之后就知道在那进行修改,但是,光修改的话,十本书就有十个相似的代码串,很不pythontic,所以,采用格式化字符串的方式进行for循环带入,方便又漂亮!

    使用了1中的解决方案还是不能定位元素
    可能查找元素的方式出现错误,我现在的使用方法是采用xpath的方式来找,比如说这样
    driver.find_element_by_xpath("/html/body/div[4]/div/div/ul/li[3]/a")虽然看起来有点长,但是元素相当好找,而且定位很准,如果采用类似这种driver.find_element_by_xpath("//ul[@id='imgmenu']/li[4]"),我现在还不能很好地驾驭,出错可能性有点大,下次要多进行尝试。
    接下来实现方案二的构思:调用PhantomJS.exe,不展现浏览器的运作,直接在cmd窗口跑(用pyinstaller打包成exe后有cmd窗)
    方案实现过程1. 效果
    2. 代码
    被调模块(可单独执行)

    # -*- coding: utf-8 -*-from selenium import webdriverimport timeimport sysfrom PIL import Image#shift-tab多行缩进(左)print 'please wait...system loading...'reload(sys)PostUrl = "http://lib.hrbeu.edu.cn/#"driver = webdriver.PhantomJS(executable_path="phantomjs.exe")#没用浏览器driver.get(PostUrl)elem_user = driver.find_element_by_name('number')elem_psw = driver.find_element_by_name('passwd')#选择我的图书馆,点击后才能看到输入账号密码click_first = driver.find_element_by_xpath("//ul[@id='imgmenu']/li[4]")click_first.click()elem_user.send_keys('S315080092')elem_psw.send_keys('xxxxxxxx')#点击登录click_second = driver.find_element_by_name('submit')click_second.click()print 'log in...'time.sleep(1)#定位新页面元素,将handle重定位即可driver.switch_to_window(driver.window_handles[1])#定位弹出的第一个页面,也就是当前页面driver.find_element_by_xpath("/html/body/div[4]/div/div/ul/li[3]/a").click()driver.save_screenshot('image_booklist.jpg')print 'turning to the mylib...'time.sleep(1)#搜索结果页面停留片刻#driver.switch_to_window(driver.window_handles[1])#没有跳出新窗口就是在同一页面的!for i in range(2,30):#这里限定是29本书,一般我们都不会借那么多书的 try: driver.find_element_by_xpath("/html/body/div[4]/div/div[2]/table/tbody/%s/td[8]/div/input"%('tr[%s]'%i)).click() print 'renewing...the %d\'th book renewed '%(i-1) except: print '%d books have been renewed !'%(i-2) a=i-2 time.sleep(4) driver.save_screenshot('image_done.jpg') print 'the picture is opening...please wait...' breaktime.sleep(2)driver.close()driver.quit()def show_img(): im_check=Image.open('image_booklist.jpg') im_check.show() im_done =Image.open('image_done.jpg') im_done.show()

    然后是程序入口

    # -*- coding: utf-8 -*-from Tkinter import *import tkMessageBoxdef check_renew(): print 'checking and renewing...' tkMessageBox.showinfo('提示','执行速度取决于网速和电脑,能等着就按"确定"\n(请允许phantomjs.exe访问网络)\nBTW 你现在按啥都不好使,程序照样执行(*゜Д゜)σ凸') from Selenium_PhantomJS_lib import show_img show_img()#show一下预约前和预约后截图,好确认 tkMessageBox.showinfo('提示','已执行成功!\n(若没有弹出图片则请自行打开程序目录)')#主框架部分root = Tk()root.title('图书馆查询续约(哈尔滨工程大学专版)--by 哈士奇说喵')label=Label(root,text=' 图书馆一键查询与续约cmd版本 (✪ω✪) ')button_check=Button(root,text='查询书单并续期━Σ(゚Д゚|||)━开启cmd无形装逼模式 ',background='green',command=check_renew)label.pack()button_check.pack()root.mainloop()

    之后启动的画面应该是这样的



    最后完成的画面应该是这样的,截图,确认框,cmd窗口,一个都不少;


    原理和上面并没有什么区别,只是调用了一个phantomjs.exe文件而已,实际上的处理都是这个exe在进行处理的,所以,在进行打包的时候,打包出来的exe需要和此文件在一个文件夹下才可以,就像这样

    遇到问题和解决方案
    找不到执行文件,phantomjs.exe
    解决方案:把phantomjs.exe添加到工作路径下,最方便的方法就是,你的工程在哪,直接添加到工程文件夹下就可以了

    截图的图片没有显示出来,或者提示”在禁用UAC时无法激活此应用“
    解决方案:图片有没有显示,可以看有没有调用show方法,如果调用了,那在自己电脑测试肯定是没有问题的,我在测试别的电脑的时候遇到UAC问题,直接启用就可以了,一般没有问题的,如果不想麻烦启动,那就直接去工作文件夹下手动打开看,截图已保存在本地的工作路径下的。
    最后这个程序是可以打包在别的电脑进行运行的,不过账号和密码我都直接输在程序里面了,而且也只是我自己学校的专版,主要还是自己用,如果有哈尔滨工程大学的小伙伴想用,你只要自己改个账号密码参数就可以了,前提是你有完整的python开发环境。
    2 评论 7 下载 2019-05-03 20:28:37 下载需要10点积分
  • 使用JDBC实现简单购物车、简单分页查询

    一、任务介绍1.1 任务描述网上购物是人们日常生活的重要事情之一。在超市中有很多日常生活的用品,如电饭煲、蒸锅、洗衣机、电冰箱等。
    本任务要求,通过所学Servlet、JavaBean和JDBC知识读取数据库数据,以JSP页面的形式呈现数据,用于数据浏览。
    备注:

    本任务需要编写2个JSP页面、2个Servlet文件(处读取商品列表信息和指定商品信息)、1-2个JavaBean文件、1个dao文件、1个service文件(实现功能)和1个数据库连接文件
    本任务所需要的类文件,需要按如右图所示结构创建
    当首次登录购买页面(访问相应的Servlet文件)时可以跳转到商品列表页面,当首次登录购物车页面(访问相应的Servlet文件)时可以有相应提示信息输出
    单击某商品图片,进入商品详细页面,并且能有分页功能
    要求商品列表页面,能够根据价格区间输入的价格范围筛选出相应的商品

    1.2 运行结果商品列表页面

    价格筛选后的商品列表页面

    商品详细页面

    1.3 任务目标
    学会分析“实现购物车”程序的实现思路
    根据思路独立完成“实现购物车”的源代码编写、编译和运行
    掌握Servlet和JSP运行原理
    掌握JavaBean、EL表达式和JSP标签库(JSTL)的使用
    掌握分页技术的原理以及实现
    熟练应用Servlet技术、JavaBean和JDBC技术完成数据访问。

    二、实现思路
    单击某商品图片,进入商品详细页面思路在<img>外层嵌套<a>标签,<a>标签设置herf属性,该属性存放商品详细信息页面的路径。
    能有分页功能思路在servlet中通过SQL语句的limit关键字实现分页查询,查询结果存放在list中,以及存放currentPage当前页面属性、totalPage总页面属性;将该数据利用request.setAttribute(string,value );传至前端页面。在JSP页面中通过${}表达式遍历输出list集合中的数据,设置4个button分别对应首页、前一页、下一页、尾页;编写<script>脚本实现点击事件的函数、分别为firstPage、previousPage、nextPage、lastPage;当条件满足时实现跳转显示下一页。【不跳转的条件,在首页按首页、前一页;在尾页按下一页、尾页】
    根据价格区间输入的价格范围筛选出相应的商品思路在servlet中利用request.getParameter(“string”);获取前端的价格区间的输入信息,在servlet实现查询信息存储在list中request.setAttribute(string,value );传至前端页面。

    三、实现代码以及运行效果Pagination(servelt)

    sy2Allbook(servlet)

    sy2SearchServelet

    四、总结或感悟4.1 错误总结
    对分页查询不熟练导致在程序显示错误
    在<script>脚本中无法跳转servlet();



    在SQLyog无法保存修改的数据
    4.2 错误解决
    利用最简单的limit关键词实现分页查询
    在csdn中学习他人方法,即在路径在加 ”./”。


    4.3 未解决错误
    在SQLyog无法保存修改的数据
    4.4 总结感悟本次实验学习到简单的分页显示功能,对<script>脚本语言的简单复习,经过这次的实验,在实验中学习到了我对前端的请求相应有了更深的理解。本实验存在不足之处在价格区间查询时未进行分页显示而是将所有信息显示在页面中,由于SQLyog的无法保存修改数据,部分的商品详细信息链接并未实现。
    0 评论 8 下载 2020-06-09 14:31:25 下载需要10点积分
  • 基于JQuery+PHP+JSON实现的注册登录修改程序

    一、实践要求要求以前后端分离的形式,运用合适的语言平台开发一个注册、登录和信息修改的小程序。
    二、实现思路2.1 总体思路
    采用JQuery+PHP+JSON完成实验
    利用三层体系结构,即模型、视图、控制器实现前端、后端分离
    利用ajax实现异步刷新页面,实现资源合理利用
    设计登录界面,实现用户登录
    设计注册页面,实现用户注册,即“增”
    设计修改页面,实现用户信息修改,即“改“

    2.2 体系结构
    2.3 开发工具与平台介绍2.3.1 Sublime TextSublime Text 是一个代码编辑器(Sublime Text 2是收费软件,但可以无限期试用),也是HTML和散文先进的文本编辑器。Sublime Text是由程序员Jon Skinner于2008年1月份所开发出来,它最初被设计为一个具有丰富扩展功能的Vim。
    2.3.2 XAMPPXAMPP(Apache+MySQL+PHP+PERL)是一个功能强大的建站集成软件包。这个软件包原来的名字是 LAMPP,但是为了避免误解,最新的几个版本就改名为 XAMPP 了。它可以在Windows、Linux、Solaris、Mac OS X 等多种操作系统下安装使用,支持多语言:英文、简体中文、繁体中文、韩文、俄文、日文等。
    2.3.3 ajaxAjax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。Ajax = 异步 JavaScript 和 XML 或者是 HTML(标准通用标记语言的子集)。Ajax 是一种用于创建快速动态网页的技术。Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
    2.3.4 JSONJSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
    2.3.5 PHP (超文本预处理器)PHP即“超文本预处理器”,是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。利于学习,使用广泛,主要适用于Web开发领域。
    2.3.6 jQueryjQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。jQuery的核心特性可以总结为:具有独特的链式语法和短小清晰的多功能接口;具有高效灵活的css选择器,并且可对CSS选择器进行扩展;拥有便捷的插件扩展机制和丰富的插件。
    2.4 注册功能
    界面:

    设置三个input文本输入框,一个为id,一个为username,一个为password填写注册信息设置一个submit对填写信息的提交设置一个超链接实现注册的页面跳转放回登录界面。
    功能:

    点击保存实现用户的信息写入数据库
    思路:通过mysqli连接MySQL数据库,将输入框中的数据保存在PHP的数组array中,利用json_encode和json_decode实现数值转换成json数据存储格式,最后利用SQL语句存入MySQL中

    关键源码
    <?php if(isset($_POST['save'])){ $conn = new mysqli('localhost', 'root', '', 'app'); $input = array( 'id' => $_POST['id'], 'username' => $_POST['username'], 'password' => $_POST['password'], ); $data[] = $input; $data = json_encode($data); $data = json_decode($data); echo $data[0]->id; foreach ($data as $user) { $sql="INSERT INTO members (id,username,password) VALUES ($user->id,'$user->username','$user->password')"; echo $sql; $result = $conn->query($sql); //查询执行成功 echo $result;//返回1表示成功 } header('location: index.php'); }?>

    2.5 登录功能
    界面:

    设置两个input文本输入框,一个为username,另一个为password输入用户名密码设置一个button登录按钮设置一个超链接实现注册的页面跳转
    关键代码
    <?phpif(!empty($_POST['username'])){ $data = array() //database details $dbHost = 'localhost'; $dbUsername = 'root'; $dbPassword = ''; $dbName = 'app'; //create connection and select DB $db = new mysqli($dbHost, $dbUsername, $dbPassword, $dbName); if($db->connect_error){ die("Unable to connect database: " . $db->connect_error); } //get user data from the database $query = $db->query("SELECT * FROM members WHERE username = {$_POST['username']} and password = {$_POST['password']}" ); if($query->num_rows > 0){ $userData = $query->fetch_assoc(); $data['status'] = 'ok'; $data['result'] = $userData; }else{ $data['status'] = 'err'; $data['result'] = ''; } //returns data as JSON format echo json_encode($data);}?>
    <script src="jquery-3.4.1.js"></script> <script> $(document).ready(function(){ $('#getUser').on('click',function(){ $.ajax({ type:'POST', url:'getData.php', dataType: "json", data: { // 要传递的数据 "username": $("#username").val(), "password": $("#password").val() }, success:function(data){ if(data.status == 'ok'){ alert("登录成功!"); window.location.href="index.php" }else{ alert("用户名或密码错误!"); } }});}); $("#username").blur(function (){ $.ajax({ type:'POST', url:'getData.php', dataType: "json", data: { // 要传递的数据 "username": $("#username").val() }, success:function(data){ if(data.status == 'ok'){ }else{ alert("用户名不存在!"); } }});});});</script>
    功能:

    用户名输入框失去焦点,判断用户是否存在
    思路:利用ID选择器,选择输入框username,利用JQuery的blur()事件判断是否失去焦点,利用ajax异步传值通过放回值,判断数据库中是否有该信息,若不存在则提示用户名不存在
    点击确认判断用户名密码是否正确。
    思路:利用ID选择器,选择输入框input,利用JQuery的click()事件判断是否触发事件,利用ajax异步传值通过放回值,判断数据库中用户名密码是否正确,它利用alert提示性


    2.6 信息修改
    界面:

    设置三个input文本输入框,一个为id,一个为username,一个为password填写修改信息设置一个submit对填写信息的提交设置一个超链接实现注册的页面跳转放回登录界面
    功能:

    点击编辑实现用户的信息修改数据库
    思路:通过mysqli连接MySQL数据库,将输入框中的数据保存在PHP的数组array中,利用json_encode和json_decode实现数值转换成json数据存储格式,最后利用SQL语句存入MySQL中

    关键代码
    <?php if(isset($_POST['save'])){ $conn = new mysqli('localhost', 'root', '', 'app'); $input = array( 'id' => $_POST['id'], 'username' => $_POST['username'], 'password' => $_POST['password'], ); //update the selected index $data_array[$index] = $input; //encode back to json $data = json_encode($data_array); $data = json_decode($data); // 解析json echo $data[0]->id; foreach ($data as $user) { $sql="update members set username='$user->username',password='$user->password' where id=$user->id"; echo $sql; $result = $conn->query($sql); //查询执行成功 echo $result;//返回1表示成功 } header('location: index.php'); }?>

    2.7 信息删除
    功能:

    点击删除实现用户的信息删除
    思路:通过mysqli连接MySQL数据库,将输入框中的数据保存在PHP的数组array中,利用json_encode和json_decode实现数值转换成json数据存储格式,最后利用SQL语句存入MySQL中

    关键代码
    <?php $index = $_GET['index']; $conn = new mysqli('localhost', 'root', '', 'app'); $data = array(); $sql = "SELECT * FROM members"; $query = $conn->query($sql); while($row = $query->fetch_assoc()){ $data[] = $row; } //convert to json $data = json_encode($data); $data_array = json_decode($data); //assign the data to selected index $row = $data_array[$index]; $data = json_encode($data, JSON_PRETTY_PRINT); $data = json_decode($data); // 解析json $sql = "delete from members where id=$row->id"; $query = $conn->query($sql); header('location: index.php'); unset($data[$index]);?>

    三、成果展示3.1 注册功能注册前

    注册

    注册完成

    3.2 登录功能登录前

    登录成功

    登陆失败

    3.3 信息修改功能修改前

    修改

    修改成功

    3.4 信息删除功能删除前

    删除成功

    四、疑难问题及解决思路
    选择实现语言出现问题

    解决:根据课设要求,选择PHP\JAVA上出现先选择Java随着进度,在写JSP作为View中利用Ajax时错误频出,以及用IDEA开发工具配置Tomcat出现系统错误,而后选择PHP作为主要实现工具
    端口配置问题,在配置环境之初出现被端口占用

    解决:通过老师的指导,以及利用网络学习如何修改端口
    Ajax不相应问题

    解决: 查找Ajax相关的资料,结合课设中老师所发的资料解决该问题

    五、总结感悟本次的课程设计,使用JQuery+PHP+JSON进行系统的开发, 在设计之余,查询过资料,了解Ajax的相关知识。在开发过程中,大大小小的会遇到些问题,在询问老师或上网查找资料的过程中,对这项开发技术的一些细节也有了更深的理解和掌握。
    由于时间比较紧张,以及设计之初选用Java最终选择用PHP做为开发语言,所以对于整体的系统美化存在一定的瑕疵,但是功能基本实现,经过这两天的课程设计体会到项目开发的的不易,以及自身知识的不足,以及快速简单入门一种语言的方法:通过网络他人总结的经验简单有效的学习。
    总的来说,本次的课程设计对我是一次很好的锻炼,让我在有限的时间对系统开发的有了新的了解。对分层体系结构有了一定的了解,前端和后端的区别、对未知领域的探索,从不了解JSON、Ajax时什么到能够独立使用其常用方法。
    去分析一个复杂的问题,一步一步进行分解,从小问题进行解决从而实现复杂的功能。
    参考资料
    [1]. [美] Lindsay Bassett (作者) 魏嘉汛 (译者):《JSON必知必会》,人民邮电出版社,2016年出版。
    [2]. [美]汤姆·马尔斯(作者)鉊钏(译者):《JSON实战》,人民邮电出版社,2017年出版。
    0 评论 7 下载 2020-06-05 20:51:43 下载需要10点积分
  • 基于Java Swing实现的简易考试系统界面搭建

    一、任务介绍1.1 任务描述本任务要搭建一个考试系统界面。考试题型主要有两类:判断题和单选题,题库是存放在两个二维数组中,要求考试题目能随机生成5到题目,并能通过左边的树形结构选择相应题型来改变右边面板的内容,具体运行效果如下。
    1.2 运行结果主界面

    判断题

    单选题

    二、任务目标
    学会分析“简易考试系统界面搭建”任务的实现思路
    根据思路独立完成“简易考试系统界面搭建”的源代码编写、编译和运行
    掌握Java动态生成组件的方法以及添加组件的方法
    掌握GUI开发过程中如何处理组件上发生的界面事件

    三、实现思路
    窗口实现思路:
    设计产生随机数作为存放二维数组的下标,设置组件JLabel存放改下标中题目,设置组件JRadioButton存放选择选择项,将组件JRadioButton存放在组件ButtonGroup将选择像设置为单选。
    阅卷取消思路:利用ButtonGroup类中的clearSelection清空每组选择的选项,通过已知产生五组题目,即生成一个ButtonGroup[]的组件组,该组的长度为五,通过
    Enumeration<AbstractButton> radioBtns = buttonGroup[i].getElements();AbstractButton btn = radioBtns.nextElement();
    获得每一个ButtonGroup[]中的选择项与答案进行比较。【利用产生题目的随机数组定位答案进行判断】

    四、实现代码及运行结果My.java
    public interface My extends MouseListener, ActionListener { public void setJButton(JButton jButton[]); public void setJRadioButton(JRadioButton jRadioButton[]); public void setButtonGroup(ButtonGroup Group[]); public void setIntA(int a[]); public void setquestion_select(String string[][]); public void setquestion_judge(String string[][]); void setTree(JTree jTree);}
    Police.java
    public class Police extends MouseAdapter implements My { JButton jButton[]; JRadioButton jRadioButton[]; ButtonGroup buttonGroup[]; JTree jTree; int a[]; String[][] question_select; String[][] question_judge; @Override public void actionPerformed(ActionEvent e) { double Mark = 0; if (e.getActionCommand().equals("确定")) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree.getLastSelectedPathComponent(); if (node.isLeaf()) { String s = node.getUserObject().toString().trim(); if (s.equals("判断")) { for (int i = 0; i < a.length; i++) { Enumeration<AbstractButton> radioBtns = buttonGroup[i].getElements(); AbstractButton btn = radioBtns.nextElement(); System.out.println(question_select[a[i]][5]); System.out.println(btn.getText()); if (question_select[a[i]][5].equals(btn.getText())) { Mark += 20; } buttonGroup[i].clearSelection(); } JOptionPane.showMessageDialog(null, "成绩:" + Mark, "成绩", JOptionPane.WARNING_MESSAGE); } else { Mark = 0; for (int i = 0; i < a.length; i++) { Enumeration<AbstractButton> radioBtns = buttonGroup[i].getElements(); AbstractButton btn = radioBtns.nextElement(); System.out.println(question_judge[a[i]][3]); System.out.println(btn.getText()); if (question_judge[a[i]][3].equals(btn.getText())) { Mark += 20; } buttonGroup[i].clearSelection(); } JOptionPane.showMessageDialog(null, "成绩:" + Mark, "成绩", JOptionPane.WARNING_MESSAGE); } } } else { for (int i = 0; i < buttonGroup.length; i++) { buttonGroup[i].clearSelection(); } } }
    Masm_test.java
    public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Masm_test window = new Masm_test(); Police police = new Police(); window.setMy(police); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the application. */ public Masm_test() { initialize(); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } /** * Initialize the contents of the frame. */ private void initialize() { frame = new JFrame(); frame.setBounds(100, 100, 609, 471); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(null); JPanel panel = new JPanel(); panel.setBounds(0, 0, 594, 419); frame.getContentPane().add(panel); panel.setLayout(null); JSplitPane splitPane = new JSplitPane(); splitPane.setBounds(0, 0, 594, 409); panel.add(splitPane); jButton = new JButton[2]; jButton[0] = new JButton("确定"); jButton[1] = new JButton("取消"); jRadioButton = new JRadioButton[4]; group = new ButtonGroup[6]; tree = new JTree(); tree.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (node.isLeaf()) { String s = node.getUserObject().toString().trim(); if (s.equals("判断")) { show(1); } else { show(0); } } } }); tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("JTree") { { add(new DefaultMutableTreeNode("\u5224\u65AD")); add(new DefaultMutableTreeNode("\u5355\u9009")); } })); splitPane.setLeftComponent(tree); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); splitPane.setRightComponent(scrollPane); } void show(int n) { JPanel panel = new JPanel(new GridLayout(7, 1, 0, 0)); a = new int[6]; for (int i = 0; i < 6; i++) { a[i] = (int) (Math.random() * (10)); for (int j = 0; j < i; j++) { if (a[j] == a[i]) { i--; } } } listener.setIntA(a); if (n == 0) { for (int i = 0; i < 6; i++) { JPanel p = new JPanel(new GridLayout(3, 1, 0, 0)); lab = new JLabel(i + 1 + "、" + question_judge[a[i]][0]); // lab.addActionListener(listener); group[i] = new ButtonGroup(); p.add(lab); for (int j = 0; j < 2; j++) { jRadioButton[j] = new JRadioButton(question_judge[a[i]][j + 1]); group[i].add(jRadioButton[j]); p.add(jRadioButton[j]); // jRadioButton[j].addActionListener(listener); } panel.add(p); } // scrollPane.setViewportView(panel); } if (n == 1) { // JPanel panel = new JPanel(new GridLayout(6, 1, 0, 0)); for (int i = 0; i < 6; i++) { JPanel p = new JPanel(new GridLayout(5, 1, 0, 0)); lab = new JLabel(i + 1 + "、" + question_select[a[i]][0]); // lab.addActionListener(listener); group[i] = new ButtonGroup(); p.add(lab); for (int j = 0; j < jRadioButton.length; j++) { jRadioButton[j] = new JRadioButton(question_select[a[i]][j + 1]); group[i].add(jRadioButton[j]); p.add(jRadioButton[j]); // jRadioButton[j].addActionListener(listener); } panel.add(p); } } scrollPane.setViewportView(panel); JPanel panel_south = new JPanel(); panel_south.add(jButton[0]); panel_south.add(jButton[1]); panel.add(panel_south); } void setMy(My listener) { this.listener = listener; for (int i = 0; i < jButton.length; i++) { jButton[i].addActionListener(listener); } listener.setButtonGroup(group); listener.setJButton(jButton); listener.setTree(tree); listener.setquestion_judge(question_judge); listener.setquestion_select(question_select); // listener.setJRadioButton(jRadioButton); }
    登入首页

    判断题

    单选题

    五、总结或感悟通过实验三,实验四的对编写代码实现窗口,熟练掌握常用组件的常用方法的使用。本次实验结合Windowbuilder插件对组件布局很快的完成实现”出卷”;
    根据实验提示选项单选的情况使用ButtonGroup存放选项radioBtns实现单选;根据提示一次出道五题想到获取每组ButtonGroup选择情况与答案进行对比实现“阅卷”。
    结合三次实验,虽然在前两次实验中使用大量的时间学习如何布局,组件的使用,触发事件的过程,但是在第三次实验体现出了前两次实验的必要性;如何合理的封装程序,实现改变ButtonGroup[]的长度便改变题目的个数,以及将窗口可见的组件做成员变量,窗口不可见的做局部变量传入事件触发后的处理类(Police)中的方法。
    0 评论 5 下载 2020-06-05 19:54:26 下载需要10点积分
  • Python基于Tkinter的二输入规则器


    Python 2.7IDE Pycharm 5.0.3
    起因
    昨天接触了Tkinter框架,之后就迫不及待的想写个计算器出来,结果呢,可想而知了,当初自己犟脾气,掌握几个语法后就想什么都不参考写自己的一段四则运算器出来,结果。。。。。。花了我一天时间,我竟然歪打正着写了个规则器出来窝草。。。。

    对比
    贴个图,别人家的计算器是这样的;而且用了五十行,说的貌似很了不起的样子(老纸的规则器,只要40-就可以!不算上Scrollbar,分割子框架这类的)


    But
    我的规则器是这样的。。。。


    我知道布局排丑了,不要在意这些细节好么0.0
    说说优点
    以计算器角度说,能完美实现计算,而且带标号,记录存储等功能,知道上一步计算结果。
    最大的优点在于二输入,调用各种def的函数,而四则运算只是最简单的函数而已,比如说我又写了字符串连接函数,相似度比较函数等等,做个实例而已,大家可以大开脑洞

    缺点
    需要键盘输入,与普通计算器按键输入不同
    我的代码冗余量比较大,因为自己需要看懂,所以不像别的教程那样直接跟着lambda和pack,一长串的,不利于我们这种小白读。等我水平再高一些,或许我也会采用lambda,这样才够pythontic~

    后续
    本身在做分类聚类方面的课题,结合这个规则器,我完全可以把k-means中的k参数在交互界面上输入,这样就不用每次上程序里面改了!还有DBSCAN里面的Eps和MinPts也可以直接用这个框架!!想想有点小激动呢!(挖的坑不计其数)
    需要优化下布局,尝试用grid来做,感觉pack里面参数略多啊。

    构思框架放代码之前,先来设计思路,我设计了两个框架,输入和输出在两个框架上,这样便于写代码思路清晰,框架大概是这样的;

    代码此代码(就算再烂)绝此一家,别无分店哈哈
    #-------------------二输入规则计算器--------------------# -*- coding: utf-8 -*-from Tkinter import *import difflib#主框架部分root = Tk()root.title('乞丐版规则器0.0')root.geometry()Label_root=Label(root,text='规则运算(根框架)',font=('宋体',15))#-----------------------定义规则------------------------def Plus(a,b): return round(a+b, 2)def Sub(a,b): return round(a-b,2)def Mult(a,b): return round(a*b, 2)def Div(a,b): return round(a/b, 2)def P_str(a,b): return a+bdef Rep(a,b): return difflib.SequenceMatcher(None,a,b).ratio() #difflib可以看看其中的定义,计算匹配率的#还可以继续增加规则函数,只要是两输入的参数都可以#----------------------触发函数-----------------------def Answ():#规则函数 if lb.get(lb.curselection()).encode('utf-8') == '加': Ans.insert(END,'规则:+ ->'+str(Plus(float(var_first.get()),float(var_second.get())))) if lb.get(lb.curselection()).encode('utf-8')=='减': Ans.insert(END,'规则:- ->'+str(Sub(float(var_first.get()),float(var_second.get())))) if lb.get(lb.curselection()).encode('utf-8')=='乘': Ans.insert(END,'规则:x ->'+str(Mult(float(var_first.get()),float(var_second.get())))) if lb.get(lb.curselection()).encode('utf-8')=='除': Ans.insert(END,'规则:/ ->'+str(Div(float(var_first.get()),float(var_second.get())))) if lb.get(lb.curselection()).encode('utf-8')=='字符串连接': Ans.insert(END,'规则:字符串连接 ->' +P_str(var_first.get(),var_second.get()).encode('utf-8')) if lb.get(lb.curselection()).encode('utf-8')=='字符串相似度': Ans.insert(END,'规则:字符串相似度 ->'+str(Rep(var_first.get(),var_second.get()))) #添加规则后定义规则函数def Clea():#清空函数 input_num_first.delete(0,END)#这里entry的delect用0 input_num_second.delete(0,END) Ans.delete(0,END)#text中的用0.0#----------------------输入选择框架--------------------frame_input = Frame(root)Label_input=Label(frame_input, text='(输入和选择框架)', font=('',15))var_first = StringVar()var_second = StringVar()input_num_first = Entry(frame_input, textvariable=var_first)input_num_second = Entry(frame_input, textvariable=var_second)#---------------------选择运算规则---------------------#还可以添加其他规则lb = Listbox(frame_input,height=4)list_item=['加', '减', '乘', '除','字符串连接','字符串相似度']for i in list_item: lb.insert(END,i)#---------------------计算结果框架---------------------frame_output = Frame(root)Label_output=Label(frame_output, text='(计算结果框架)', font=('',15))Ans = Listbox(frame_output, height=5,width=30)#text也可以,Listbox好处在于换行#-----------------------Button-----------------------calc = Button(frame_output,text='计算', command=Answ)cle = Button(frame_output,text='清除', command=Clea)#---------------------滑动Scrollbar-------------------scr1 = Scrollbar(frame_input)lb.configure(yscrollcommand = scr1.set)scr1['command']=lb.yviewscr2 = Scrollbar(frame_output)Ans.configure(yscrollcommand = scr2.set)scr2['command']=Ans.yview#-------------------------布局------------------------#布局写在一块容易排版,可能我low了吧Label_root.pack(side=TOP)frame_input.pack(side=TOP)Label_input.pack(side=LEFT)input_num_first.pack(side=LEFT)lb.pack(side=LEFT)scr1.pack(side=LEFT,fill=Y)input_num_second.pack(side=RIGHT)frame_output.pack(side=TOP)Label_output.pack(side=LEFT)calc.pack(side=LEFT)cle.pack(side=LEFT)Ans.pack(side=LEFT)scr2.pack(side=LEFT,fill=Y)#-------------------root.mainloop()------------------root.mainloop()
    Tkinter还是比较好上手的,知道一些基本语法就可以实现自己想要的效果了,这里我把自己遇到的问题写一下,如果也有人遇到,恰好能帮助的话,我很荣幸。
    问题&解决Q.button或插件不显示A.记得加上pack显示函数!!一般我都定义完了插件直接补上 pack函数
    Q.插件位置显示问题A.这个要看你的pack函数写在哪了,所以我一般直接写在最后,容易排序,比如side都是LEFT的话,就按先后顺序显示的
    Q.刚开始键入的被get之后,直接运算出错。A.结果是str类型,所以记得用float强制转换,不用int是因为int做除法时候不好使,需要float,切记(python2.7)
    Pay Attention
    在自定义规则的时候,主要get抓到的数据类型和你的def里面的数据类型,保持一致。
    清空函数中,text和entry,listbox的delect清空不一样!比如被实例的是Listbox(Entry)的,那么清空是Obj.delect(0,END),而如果是Text的对象,那么就是Obj.delect(0.0,END),这个是我之前没想到的,只有实践过才记得住把。而且,用listbox好处在于计算一个值之后,下一个值自动换行,用text时候\n还不好使
    如果使用python3,会出现,no model name Tkinter,其实py3只是把它改成小写了,所以导入包的时候改成tkinter 小写就行
    出现点击运算符之后无法输出结果或者gui中文乱码问题,一般也是出现在python3的问题上,所以解决方案是吧encode(‘utf-8’)删掉就可以了。
    2 评论 2 下载 2019-04-27 21:09:19 下载需要10点积分
  • 基于Bootstrap框架和SSH框架实现的旅游自助系统网站APP

    1 需求分析1.1 五类地方旅游类App下载量分布图从下载量来看,交通出行类App显然是最受用户欢迎的,在数量少于景点攻略类App的情况下,交通出行类App总下载量为前者2.43倍,占总下载量的70%。六大平台中仅有应用宝上,交通出行类App总下载量低于景点攻略类App。

    1.2 六大商店地方旅游类App下载量分布图六大商店地方旅游类App下载量显示,在百度手机助手上线的地方旅游类App总计下载量为8912449次,明显领先360助手、安卓市场、安智市场、豌豆荚、应用宝五家商店。

    2 可行性分析经济可行性

    服务器:Linux系统的阿里云服务器
    PC机:开发电脑3台
    数据库:MySQL
    建模工具:Rotational Rose 2003

    技术可行性

    版本控制系统:SVN
    前端:Bootstrap框架、Html5+CSS3、JavaScript、Ajax
    后台:Struts2框架、Hibernate框架、Spring框架
    设计模式:拟采用单例模式、适配器和外观模式
    算法:AES加密算法、MD5加密算法、路径规划算法

    社会因素可行性分析

    所有软件都选用正版
    所有技术资料都由提出方保管
    合同制定确定违约责任
    用户使用可行性分析

    3 分析图用例建模


    流程图
    系统分析
    时序图
    E-R图



    数据库设计
    四、关键技术
    版本控制系统:SVN
    前端:Bootstrap框架、Html5+CSS3、JavaScript、Ajax
    后台:Struts2框架、Hibernate框架、Spring框架
    设计模式:拟采用单例模式、适配器和外观模式
    算法:AES加密算法、MD5加密算法、路径规划算法



    五、模块测试景点和旅游路线的查询,支持模糊查询



    预定旅游服务,用户登录注册之后就可以预定旅游服务

    后台管理系统,旅游公司的管理员可以进行接收旅游服务订票操作


    旅游公司管理员可以新开旅游路线

    维护旅游公司的旅游路线

    开发景点,支持图片上传,带Jquery的城市选择器

    进行景点维护,采用UEditor富文本编辑器框架进行编辑,可以将样式写入数据库
    2 评论 48 下载 2018-11-28 11:37:13 下载需要12点积分
  • Python自定义豆瓣电影种类,排行,点评的爬取与存储(初级)


    Python 2.7
    IDE Pycharm 5.0.3
    Firefox 47.0.1

    起因
    就是想写个豆瓣电影的爬取,给我电影荒的同学。。。。当然自己也练手啦

    目的
    根据用户输入,列出豆瓣高分TOP(用户自定义)的电影,链接,及热评若干。
    制作不需要Python环境可运行的exe,但由于bug未修复,需要火狐浏览器支持

    方案
    使用PhantomJS+Selenium+Firefox实现

    实现过程
    get到首页后,根据选择,点击种类,然后根据输入需求,进行排序
    抓取每个电影及超链接,进入超链接后,抓取当前电影的热评及长评
    当用户所要求TOP数目大于第一页的20个时候,点击加载更多,再出现20个电影,重复2操作


    以豆瓣高分,然后按评分排序的点击过程(其余操作一致,先种类后排序选择,再爬)


    实现代码# -*- coding: utf-8 -*-#Author:哈士奇说喵#爬豆瓣高分电影及hot影评from selenium import webdriverimport selenium.webdriver.support.ui as uiimport timeprint "---------------system loading...please wait...---------------"SUMRESOURCES = 0 #全局变量driver_detail = webdriver.PhantomJS(executable_path="phantomjs.exe")#driver_item=webdriver.PhantomJS(executable_path="phantomjs.exe")driver_item=webdriver.Firefox()url="https://movie.douban.com/"#等待页面加载方法wait = ui.WebDriverWait(driver_item,15)wait1 = ui.WebDriverWait(driver_detail,15)#获取URL和文章标题def getURL_Title(): global SUMRESOURCES###############################################################################需要键入想要获取的信息,比如种类,排序方式,想看多少内容############################################################################## print "please select:" kind=input("1-Hot\n2-Newest\n3-Classics\n4-Playable\n5-High Scores\n6-Wonderful but not popular\n7-Chinese film\n8-Hollywood\n9-Korea\n10-Japan\n11-Action movies\n12-Comedy\n13-Love story\n14-Science fiction\n15-Thriller\n16-Horror film\n17-Cartoon\nplease select:") print "--------------------------------------------------------------------------" sort=input("1-Sort by hot\n2-Sort by time\n3-Sort by score\nplease select:") print "--------------------------------------------------------------------------" number = input("TOP ?:") print "--------------------------------------------------------------------------" ask_long=input("don't need long-comments,enter 0,i like long-comments enter 1:") print "--------------------------------------------------------------------------" global save_name save_name=raw_input("save_name (xx.txt):") print "---------------------crawling...---------------------" driver_item.get(url)###############################################################################进行网页get后,先进行电影种类选择的模拟点击操作,然后再是排序方式的选择#最后等待一会,元素都加载完了,才能开始爬电影,不然元素隐藏起来,不能被获取#wait.until是等待元素加载完成!############################################################################## wait.until(lambda driver: driver.find_element_by_xpath("//div[@class='fliter-wp']/div/form/div/div/label[%s]"%kind)) driver_item.find_element_by_xpath("//div[@class='fliter-wp']/div/form/div/div/label[%s]"%kind).click() wait.until(lambda driver: driver.find_element_by_xpath("//div[@class='fliter-wp']/div/form/div[3]/div/label[%s]"%sort)) driver_item.find_element_by_xpath("//div[@class='fliter-wp']/div/form/div[3]/div/label[%s]"%sort).click() num=number+1#比如输入想看的TOP22,那需要+1在进行操作,细节问题 time.sleep(2) #打开几次“加载更多” num_time = num/20+1 wait.until(lambda driver: driver.find_element_by_xpath("//div[@class='list-wp']/a[@class='more']")) for times in range(1,num_time): time.sleep(1) driver_item.find_element_by_xpath("//div[@class='list-wp']/a[@class='more']").click() time.sleep(1) wait.until(lambda driver: driver.find_element_by_xpath("//div[@class='list']/a[%d]"%num)) #print '点击\'加载更多\'一次' #使用wait.until使元素全部加载好能定位之后再操作,相当于try/except再套个while把 for i in range(1,num): wait.until(lambda driver: driver.find_element_by_xpath("//div[@class='list']/a[%d]"%num)) list_title=driver_item.find_element_by_xpath("//div[@class='list']/a[%d]"%i) print '----------------------------------------------'+'NO' + str(SUMRESOURCES +1)+'----------------------------------------------' print u'电影名: ' + list_title.text print u'链接: ' + list_title.get_attribute('href') #print unicode码自动转换为utf-8的 #写入txt中部分1 list_title_wr=list_title.text.encode('utf-8')#unicode码,需要重新编码再写入txt list_title_url_wr=list_title.get_attribute('href') Write_txt('\n----------------------------------------------'+'NO' + str(SUMRESOURCES +1)+'----------------------------------------------','',save_name) Write_txt(list_title_wr,list_title_url_wr,save_name) SUMRESOURCES = SUMRESOURCES +1 try:#获取具体内容和评论。href是每个超链接也就是资源单独的url getDetails(str(list_title.get_attribute('href')),ask_long) except: print 'can not get the details!'###############################################################################当选择一部电影后,进入这部电影的超链接,然后才能获取#同时别忽视元素加载的问题#在加载长评论的时候,注意模拟点击一次小三角,不然可能会使内容隐藏##############################################################################def getDetails(url,ask_long): driver_detail.get(url) wait1.until(lambda driver: driver.find_element_by_xpath("//div[@id='link-report']/span")) drama = driver_detail.find_element_by_xpath("//div[@id='link-report']/span") print u"剧情简介:"+drama.text drama_wr=drama.text.encode('utf-8') Write_txt(drama_wr,'',save_name) print "--------------------------------------------Hot comments TOP----------------------------------------------" for i in range(1,5):#四个短评 try: comments_hot = driver_detail.find_element_by_xpath("//div[@id='hot-comments']/div[%s]/div/p"%i) print u"最新热评:"+comments_hot.text comments_hot_wr=comments_hot.text.encode('utf-8') Write_txt("--------------------------------------------Hot comments TOP%d----------------------------------------------"%i,'',save_name) Write_txt(comments_hot_wr,'',save_name) except: print 'can not caught the comments!' #加载长评 if ask_long==1: try: driver_detail.find_element_by_xpath("//img[@class='bn-arrow']").click() #wait.until(lambda driver: driver.find_element_by_xpath("//div[@class='review-bd']/div[2]/div/div")) time.sleep(1) #解决加载长评会提示剧透问题导致无法加载 comments_get = driver_detail.find_element_by_xpath("//div[@class='review-bd']/div[2]/div") if comments_get.text.encode('utf-8')=='提示: 这篇影评可能有剧透': comments_deep=driver_detail.find_element_by_xpath("//div[@class='review-bd']/div[2]/div[2]") else: comments_deep = comments_get print "--------------------------------------------long-comments---------------------------------------------" print u"深度长评:"+comments_deep.text comments_deep_wr=comments_deep.text.encode('utf-8') Write_txt("--------------------------------------------long-comments---------------------------------------------\n",'',save_name) Write_txt(comments_deep_wr,'',save_name) except: print 'can not caught the deep_comments!'###############################################################################将print输出的写入txt中查看,也可以在cmd中查看,换行符是为了美观##############################################################################def Write_txt(text1='',text2='',title='douban.txt'): with open(title,"a") as f: for i in text1: f.write(i) f.write("\n") for j in text2: f.write(j) f.write("\n")def main(): getURL_Title() driver_item.quit()main()
    上面的代码是可以实现的,但需要Firefox的配合,因为我其中一个引擎调用了Firefox,另一个抓评论的用了PhantomJS。
    实现效果

    存入的txt文件



    因为打包成exe必须是中文的键入,所以没办法,我改成英文来着,不然会出现这种情况。。。



    输出内容是没有问题的。。。。。。

    问题及解决方案Q: 使用PhantomJS和Firefox出现不同效果的问题,第21个回到起点。
    A: 解决方案,暂且我也没有找到,只有调用Firefox然后完事后再关闭,分析请见伪解决Selenium中调用PhantomJS无法模拟点击(click)操作
    Q: 在对unicode输出在txt出现的问题,但是在print可以直接中文输出的。
    A: 解决方案:详见Python输出(print)内容写入txt中保存
    Q: 元素无法定位问题
    A: 首先查看是不是隐藏元素,其次再看自己的规则有没有写错,还有就是是不是页面加载未完成,详见解决网页元素无法定位(NoSuchElementException: Unable to locate element)的几种方法
    Q: 只采集自己需要的数据,剔除无用数据,比如说,刚开始我用
    driver_detail.find_elements_by_xpath然后写个取出list中元素的方法,但是这样的话,一个便签下内容未必太多,并不是我想要的如图:

    比如说,我只想要红色的部分,那么,采取elements就不太好处理。
    A: 我采用的方法是格式化字符串!根据元素的特性,可以发现,每个热评的正文标签不一样的,其余标签一样,只要格式化正文标签即可,像这样
    for i in range(1,5):#取了前四条热评 try: comments = driver_detail.find_element_by_xpath("//div[@id='hot-comments']/div[%s]/div/p"%i) print u"最新热评:"+comments.text except: print 'can not caught comments!'
    Q: 一个引擎干有个事!我现在没办法,只有将第一个需要处理的页面用Firefox来处理,之后评论用PhantomJS来抓取,之后可以用quit来关闭浏览器,但是启动浏览器还是会耗费好多资源,而且挺慢,虽然PhantomJS也很慢,我12G内存都跑完了。。。。。。看样子是给我买8x2 16G双通道的借口啊。
    Q: 备注不标准也会导致程序出错,这个是我没想到的,我一直以为在’’’备注’’’之间的都可以随便来,结果影响程序运行了,之后分模块测试才注意到这个问题,也是以前没有遇到过的,切记!需要规范自己代码,特别是像Python这样缩进是灵魂的语言。。。。
    Q: 补充,长评论的抓取

    这是点击之后的图,可以看到元素定位也是不一样的,注意
    2 评论 5 下载 2019-04-26 22:37:06 下载需要10点积分
显示 15 到 30 ,共 15 条
eject