本文整理自网络,侵删。
目录
- 背景
- 用到的技术
- 主要流程
- 代码模块
- Joke对象
- 爬虫抓取笑话
- 代码实现
- 保存到sqlite数据库
- 抓取笑话并保存到数据库
背景
当我慢慢的开在高速公路上,宽敞的马路非常的拥挤!这时候我喜欢让百度导航的小度给我讲笑话,但她有点弱,每次只能讲一个。
百度号称要发力人工智能,成为国内人工智能的领军企业。但从小度的智商和理解能力上,我对此非常怀疑。
所以我们干脆用Python来开发一个可以讲笑话的机器人,可以自由定制功能,想讲几个笑话就讲几个笑话。
用到的技术
本文用到以下技术:
爬虫 - 抓取笑话
数据库 - 用sqlite保存笑话
面向对象 - 封装joke对象
模块 - 代码分模块放在多个文件中
语音识别 - 识别用户输入的语音,把笑话转换成语音
GUI - 开发简单的用户界面
打包 - 把程序打包成可执行文件
主要流程
代码模块
为了代码结构清晰,方便维护,我们把代码放到了多个py文件中,每个文件各司其职。
本程序共包括一下几个代码模块:
joke.py - 笑话对象,被多个模块共用
joke_crawler.py - 笑话爬虫
joke_db.py - 处理数据库相关,保存笑话,查询笑话等
joke_ui.py - 用户界面模块
joke_audio.py - 处理和语音相关的任务 和2个非代码结构:
joke_audio - 存放语音文件的文件夹
jokeDB.db - sqlite3数据库文件
现在开始写代码,请先创建一个文件夹,建议取名为myjoke。后面所有的代码都在这个文件夹中。
Joke对象
我们使用面向对象的编程思想,创建一个叫做Joke的类,来表示一个笑话。
用了Joke类,代码更清晰,数据传输也更方便。Joke类会被所有其他的模块用到。
创建一个名为joke.py的文件
代码如下:
class Joke: ? ? ''' ? ? 表示一个笑话。 ? ? 其中title是笑话标题,detail是笑话内容 ? ? url是笑话的采集网址,通过url判定笑话是否重复,防止保存重复笑话 ? ? id是数据库生成的唯一标识符,刚刚采集下来的笑话是没有id的,所以id可以为空 ? ? ''' ? ? def __init__(self, title, detail, url, id=None): ? ? ? ? self.title = title ? ? ? ? self.detail = detail ? ? ? ? self.url = url ? ? ? ? self.id = id ? ? def __str__(self): ? ? ? ? ''' ? ? ? ? 有了这个方法,print(joke)会把笑话打印成下面格式的字符串,否则只会打印对象的内存地址 ? ? ? ? ''' ? ? ? ? return f'{id}-{title}\n{detail}\n{url}'
这个类中只有两个魔术方法,一个是构造函数__init__,一个是__str__。
爬虫抓取笑话
分析网页结构
我们要抓取的网址是这个:http://xiaohua.zol.com.cn/detail1/1.html 我们要抓的数据点有三个:
在谷歌浏览器中,右键点击检查,就可以在下面看到网页的代码结构:
1.用鼠标点击1的按钮
2.然后把鼠标移到2的地方
3.就可以看到成功这两个字在网页中的结构。
通过分析这个结构,我们可以得出:成功这两个字是在一个h1结构内,这个h1的class是article-title,因为可以使用这个特征提取其中的内容(示例代码):
title = html.select_one('h1.article-title').getText()
用同样的方法可以分析出笑话内容和下一页URL的特征。
分析网页结构需要基本的HTML和CSS的知识,如果完全不懂,可以先直接模仿我的代码,然后再慢慢理解相关知识。
代码实现
现在来看完整的代码。
新建一个名为joke_crawler.py的文件。
import requests import bs4 import time import random #先注释掉数据库相关的代码,后面需要反注释回来 #import joke_db from joke import Joke #起始URL url = 'http://xiaohua.zol.com.cn/detail1/1.html' #网站的域名地址,用来拼接完整地址 host = 'http://xiaohua.zol.com.cn' def craw_joke(url): ''' 抓取指定的URL,返回一个Joke对象,和下一个要抓取的URL 如果抓取失败,返回None, None 必须设置User-Agent header,否则容易被封 ''' print(f'正在抓取:{url}') headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36' } html = requests.get(url, headers=headers).text soup = bs4.BeautifulSoup(html, 'lxml') try: #分别使用css选择器提取title, detail和next_url title = soup.select_one('h1.article-title').getText() detail = soup.select_one('div.article-text').getText().strip() next_url = soup.select_one('span.next > a')['href'] return Joke(title, detail, url), next_url except Exception as e: print('出错了:', e) print(html) return None, None # 抓取笑话,以学习为目的,建议不要抓取太多,本例子只抓取了10个 count = 0 for i in range(0, 10): joke, next_url = craw_joke(url) if joke: #先注释掉数据库相关的代码,后面需要反注释回来 #joke_db.save(joke) print(joke) url = host + next_url print('歇一会儿再抓!') time.sleep(random.randint(1, 5)) print('抓完收工!')
代码中已经添加了一些注释,有基础的应该可以看懂。
有两个点要注意:
1.在craw_joke函数中,必须添加User-Agent的header,否则会很快被封锁。
2.代码中注释掉了和数据库相关的代码,现在只是把笑话打印出来。写好了数据库模块,要把相关代码反注释回来。
3.抓取的中间有随机1到5秒的停顿,一个防止被封锁,二是出于文明礼貌,不要给服务器带来太大压力。
保存到sqlite数据库
抓来的笑话可以保存到文件中,但是用文件存储不方便检索,也不方便判断笑话是否重复等。
所以更好的方法是把笑话保存到数据库,这里选择sqlite做数据库。原因如下:
1.sqlite是文件数据库,不需要安装额外的数据库服务器
2.python默认支持sqlite数据库,不需要任何额外的安装和配置
但如果你想把世界上所有的笑话都抓下来,数据量很大,那建议使用更正式的数据库,比如MySQL.
相关阅读 >>
微软官方sqlhelper类 数据库辅助操作类 font color=red原创font
android开发之contentprovider的使用详解
Sqlite expert pro5.0如何安装可视化数据库管理软件激活教程
更多相关阅读请进入《Sqlite》频道 >>

数据库系统概念 第6版
机械工业出版社
本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。
转载请注明出处:木庄网络博客 » Python人工智能实战之对话机器人的实现
相关推荐
评论
管理员已关闭评论功能...