Python爬取成语接龙类网站


Posted in Python onOctober 19, 2018

介绍

本文将展示如何利用Python爬虫来实现诗歌接龙。

该项目的思路如下:

利用爬虫爬取诗歌,制作诗歌语料库;

将诗歌分句,形成字典:键(key)为该句首字的拼音,值(value)为该拼音对应的诗句,并将字典保存为pickle文件;
读取pickle文件,编写程序,以exe文件形式运行该程序。

该项目实现的诗歌接龙,规则为下一句的首字与上一句的尾字的拼音(包括声调)一致。下面将分步讲述该项目的实现过程。

诗歌语料库

首先,我们利用Python爬虫来爬取诗歌,制作语料库。爬取的网址为:https://www.gushiwen.org,页面如下:

Python爬取成语接龙类网站

由于本文主要为试了展示该项目的思路,因此,只爬取了该页面中的唐诗三百首、古诗三百、宋词三百、宋词精选,一共大约1100多首诗歌。为了加速爬虫,采用并发实现爬虫,并保存到poem.txt文件。完整的Python程序如下:

import re
import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED

# 爬取的诗歌网址
urls = ['https://so.gushiwen.org/gushi/tangshi.aspx',
  'https://so.gushiwen.org/gushi/sanbai.aspx',
  'https://so.gushiwen.org/gushi/songsan.aspx',
  'https://so.gushiwen.org/gushi/songci.aspx'
  ]

poem_links = []
# 诗歌的网址
for url in urls:
 # 请求头部
 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}
 req = requests.get(url, headers=headers)

 soup = BeautifulSoup(req.text, "lxml")
 content = soup.find_all('div', class_="sons")[0]
 links = content.find_all('a')

 for link in links:
  poem_links.append('https://so.gushiwen.org'+link['href'])

poem_list = []
# 爬取诗歌页面
def get_poem(url):
 #url = 'https://so.gushiwen.org/shiwenv_45c396367f59.aspx'
 # 请求头部
 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}
 req = requests.get(url, headers=headers)
 soup = BeautifulSoup(req.text, "lxml")
 poem = soup.find('div', class_='contson').text.strip()
 poem = poem.replace(' ', '')
 poem = re.sub(re.compile(r"\([\s\S]*?\)"), '', poem)
 poem = re.sub(re.compile(r"([\s\S]*?)"), '', poem)
 poem = re.sub(re.compile(r"。\([\s\S]*?)"), '', poem)
 poem = poem.replace('!', '!').replace('?', '?')
 poem_list.append(poem)

# 利用并发爬取
executor = ThreadPoolExecutor(max_workers=10) # 可以自己调整max_workers,即线程的个数
# submit()的参数: 第一个为函数, 之后为该函数的传入参数,允许有多个
future_tasks = [executor.submit(get_poem, url) for url in poem_links]
# 等待所有的线程完成,才进入后续的执行
wait(future_tasks, return_when=ALL_COMPLETED)

# 将爬取的诗句写入txt文件
poems = list(set(poem_list))
poems = sorted(poems, key=lambda x:len(x))
for poem in poems:
 poem = poem.replace('《','').replace('》','') \
    .replace(':', '').replace('“', '')
 print(poem)
 with open('F://poem.txt', 'a') as f:
  f.write(poem)
  f.write('\n')

该程序爬取了1100多首诗歌,并将诗歌保存至poem.txt文件,形成我们的诗歌语料库。当然,这些诗歌并不能直接使用,需要清理数据,比如有些诗歌标点不规范,有些并不是诗歌,只是诗歌的序等等,这个过程需要人工操作,虽然稍显麻烦,但为了后面的诗歌分句效果,也是值得的。

诗歌分句

有了诗歌语料库,我们需要对诗歌进行分句,分句的标准为:按照结尾为。?!进行分句,这可以用正则表达式实现。之后,将分句好的诗歌写成字典:键(key)为该句首字的拼音,值(value)为该拼音对应的诗句,并将字典保存为pickle文件。完整的Python代码如下:

import re
import pickle
from xpinyin import Pinyin
from collections import defaultdict

def main():
 with open('F://poem.txt', 'r') as f:
  poems = f.readlines()

 sents = []
 for poem in poems:
  parts = re.findall(r'[\s\S]*?[。?!]', poem.strip())
  for part in parts:
   if len(part) >= 5:
    sents.append(part)

 poem_dict = defaultdict(list)
 for sent in sents:
  print(part)
  head = Pinyin().get_pinyin(sent, tone_marks='marks', splitter=' ').split()[0]
  poem_dict[head].append(sent)

 with open('./poemDict.pk', 'wb') as f:
  pickle.dump(poem_dict, f)

main()

我们可以看一下该pickle文件(poemDict.pk)的内容:

Python爬取成语接龙类网站

当然,一个拼音可以对应多个诗歌。

诗歌接龙

读取pickle文件,编写程序,以exe文件形式运行该程序。

为了能够在编译形成exe文件的时候不出错,我们需要改写xpinyin模块的_init_.py文件,将该文件的全部代码复制至mypinyin.py,并将代码中的下面这句代码

data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
        'Mandarin.dat')

改写为

data_path = os.path.join(os.getcwd(), 'Mandarin.dat')

这样我们就完成了mypinyin.py文件。

接下来,我们需要编写诗歌接龙的代码(Poem_Jielong.py),完整代码如下:

import pickle
from mypinyin import Pinyin
import random
import ctypes

STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12

FOREGROUND_DARKWHITE = 0x07 # 暗白色
FOREGROUND_BLUE = 0x09 # 蓝色
FOREGROUND_GREEN = 0x0a # 绿色
FOREGROUND_SKYBLUE = 0x0b # 天蓝色
FOREGROUND_RED = 0x0c # 红色
FOREGROUND_PINK = 0x0d # 粉红色
FOREGROUND_YELLOW = 0x0e # 黄色
FOREGROUND_WHITE = 0x0f # 白色

std_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)

# 设置CMD文字颜色
def set_cmd_text_color(color, handle=std_out_handle):
 Bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
 return Bool

# 重置文字颜色为暗白色
def resetColor():
 set_cmd_text_color(FOREGROUND_DARKWHITE)

# 在CMD中以指定颜色输出文字
def cprint(mess, color):
 color_dict = {
     '蓝色': FOREGROUND_BLUE,
     '绿色': FOREGROUND_GREEN,
     '天蓝色': FOREGROUND_SKYBLUE,
     '红色': FOREGROUND_RED,
     '粉红色': FOREGROUND_PINK,
     '黄色': FOREGROUND_YELLOW,
     '白色': FOREGROUND_WHITE
     }
 set_cmd_text_color(color_dict[color])
 print(mess)
 resetColor()

color_list = ['蓝色','绿色','天蓝色','红色','粉红色','黄色','白色']

# 获取字典
with open('./poemDict.pk', 'rb') as f:
 poem_dict = pickle.load(f)

#for key, value in poem_dict.items():
 #print(key, value)

MODE = str(input('Choose MODE(1 for 人工接龙, 2 for 机器接龙): '))

while True:
 try:
  if MODE == '1':
   enter = str(input('\n请输入一句诗或一个字开始:'))
   while enter != 'exit':
    test = Pinyin().get_pinyin(enter, tone_marks='marks', splitter=' ')
    tail = test.split()[-1]
    if tail not in poem_dict.keys():
     cprint('无法接这句诗。\n', '红色')
     MODE = 0
     break
    else:
     cprint('\n机器回复:%s'%random.sample(poem_dict[tail], 1)[0], random.sample(color_list, 1)[0])
     enter = str(input('你的回复:'))[:-1]

   MODE = 0

  if MODE == '2':
   enter = input('\n请输入一句诗或一个字开始:')

   for i in range(10):
    test = Pinyin().get_pinyin(enter, tone_marks='marks', splitter=' ')
    tail = test.split()[-1]
    if tail not in poem_dict.keys():
     cprint('------>无法接下去了啦...', '红色')
     MODE = 0
     break
    else:
     answer = random.sample(poem_dict[tail], 1)[0]
     cprint('(%d)--> %s' % (i+1, answer), random.sample(color_list, 1)[0])
     enter = answer[:-1]

   print('\n(*****最多展示前10回接龙。*****)')
   MODE = 0

 except Exception as err:
  print(err)
 finally:
  if MODE not in ['1','2']:
   MODE = str(input('\nChoose MODE(1 for 人工接龙, 2 for 机器接龙): '))

现在整个项目的结构如下(Mandarin.dat文件从xpinyin模块对应的文件夹下复制过来):

Python爬取成语接龙类网站

切换至该文件夹,输入以下命令即可生成exe文件:

pyinstaller -F Poem_jielong.py

Python爬取成语接龙类网站

本项目的诗歌接龙有两种模式,一种为人工接龙,就是你先输入一句诗或一个字,然后就是计算机回复一句,你回复一句,负责诗歌接龙的规则;另一种模式为机器接龙,就是你先输入一句诗或一个字,机器会自动输出后面的接龙诗句(最多10个)。

先测试人工接龙模式:

Python爬取成语接龙类网站

再测试机器接龙模式:

Python爬取成语接龙类网站

总结

该项目的Github地址为:https://github.com/percent4/Shicijielong

Python 相关文章推荐
重命名批处理python脚本
Apr 05 Python
Python socket编程实例详解
May 27 Python
使用pdb模块调试Python程序实例
Jun 02 Python
python学习笔记--将python源文件打包成exe文件(pyinstaller)
May 26 Python
PyQt5 多窗口连接实例
Jun 19 Python
python excel转换csv代码实例
Aug 26 Python
使用Python实现批量ping操作方法
May 06 Python
基于Python组装jmx并调用JMeter实现压力测试
Nov 03 Python
python实现的人脸识别打卡系统
May 08 Python
Python Django框架介绍之模板标签及模板的继承
May 27 Python
简单且有用的Python数据分析和机器学习代码
Jul 02 Python
python自动化测试通过日志3分钟定位bug
Nov 20 Python
将Django项目部署到CentOs服务器中
Oct 18 #Python
python中将zip压缩包转为gz.tar的方法
Oct 18 #Python
Python 忽略warning的输出方法
Oct 18 #Python
解决python通过cx_Oracle模块连接Oracle乱码的问题
Oct 18 #Python
解决python3捕获cx_oracle抛出的异常错误问题
Oct 18 #Python
python 自定义异常和异常捕捉的方法
Oct 18 #Python
详解Python发送email的三种方式
Oct 18 #Python
You might like
一个从别的网站抓取信息的例子(域名查询)
2006/10/09 PHP
浅析PHP程序防止ddos,dns,集群服务器攻击的解决办法
2013/06/18 PHP
thinkphp判断访客为手机端或PC端的方法
2014/11/24 PHP
PHP查找与搜索数组元素方法总结
2015/06/12 PHP
Symfony2创建基于域名的路由相关示例
2016/11/14 PHP
php 删除指定文件夹的实例讲解
2017/07/25 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
基于php流程控制语句和循环控制语句(讲解)
2017/10/23 PHP
PHP开发实现微信退款功能示例
2017/11/25 PHP
PHP命名空间与自动加载类详解
2018/09/04 PHP
jQuery入门知识简介
2010/03/04 Javascript
jQuery Clone Bug解决代码
2010/12/22 Javascript
js中事件的处理与浏览器对象示例介绍
2013/11/29 Javascript
封装好的一个万能检测表单的方法
2015/01/21 Javascript
js进行表单验证实例分析
2015/02/10 Javascript
jquery仿百度经验滑动切换浏览效果
2015/04/14 Javascript
Jquery操作Ajax方法小结
2015/11/29 Javascript
js自定义QQ菜单效果
2017/01/10 Javascript
解决vue keep-alive 数据更新的问题
2018/09/21 Javascript
JavaScript this绑定过程深入详解
2018/12/07 Javascript
微信小程序如何实现点击图片放大功能
2020/01/21 Javascript
js实现整体缩放页面适配移动端
2020/03/31 Javascript
JavaScript 判断数据类型的4种方法
2020/09/11 Javascript
Python的词法分析与语法分析
2013/05/18 Python
使用python实现strcmp函数功能示例
2014/03/25 Python
python解析基于xml格式的日志文件
2017/02/25 Python
Python json 错误xx is not JSON serializable解决办法
2017/03/15 Python
python微信撤回监测代码
2019/04/29 Python
HTML的form表单和django的form表单
2019/07/25 Python
Python Pillow(PIL)库的用法详解
2020/09/19 Python
python中pyplot基础图标函数整理
2020/11/10 Python
Java的for语句中break, continue和return的区别
2013/12/19 面试题
研究生导师评语
2014/12/31 职场文书
2016年师德学习心得体会
2016/01/12 职场文书
2016年教师党员公开承诺书
2016/03/24 职场文书
html5调用摄像头实例代码
2021/06/28 HTML / CSS