没错,我一贯探索用高新技能来激活传统文化,用传统文化来滋养高新技能。
这不,我打算写一个基于TensorFlow的自动对春联的程序。经由考试测验,目前已经完成了。
Input是人工输入的上联,Output是机器自动给出的下联。
Input: <start> 神 州 万 里 春 光 美 <end> [2, 61, 27, 26, 43, 4, 20, 78, 3] Output:<start> 祖 国 两 制 好 事 兴 <end> [2, 138, 11, 120, 428, 73, 64, 46, 3]Input: <start> 爆 竹 迎 新 春 <end> [2, 167, 108, 23, 9, 4, 3]Output: <start> 瑞 雪 兆 丰 年 <end> [2, 92, 90, 290, 30, 8, 3]Input: <start> 金 牛 送 寒 去 <end> [2, 63, 137, 183, 302, 101, 3]Output: <start> 玉 鼠 喜 春 来 <end> [2, 126, 312, 17, 4, 26, 3]Input: <start> 锦 绣 花 似 锦 <end> [2, 68, 117, 8, 185, 68, 3]Output: <start> 缤 纷 春 如 风 <end> [2, 1651, 744, 4, 140, 7, 3]Input: <start> 春 风 送 暖 山 河 好 <end> [2, 4, 5, 183, 60, 7, 71, 45, 3]Output: <start> 瑞 雪 迎 春 世 纪 新 <end> [2, 92, 90, 27, 4, 36, 99, 5, 3]Input: <start> 百 花 争 艳 春 风 得 意 <end> [2, 48, 8, 164, 76, 4, 5, 197, 50, 3]Output: <start> 万 马 奔 腾 喜 气 福 多 <end> [2, 6, 28, 167, 58, 17, 33, 15, 113, 3]复制代码
2. 实现
人工智能的背后是大量数据的演习,而仅仅这些演习数据就让人很难堪:找不到啊。
网络上有一个开源的对对联项目,里面有一个70万条的对联数据集,项目地址如下:GitHub - wb14123/couplet-dataset: Dataset for couplets. 70万条对联数据库。
但是,我并不满意,由于我要的是春联,不是对联。
对联虽然包含了春联,但是春联是带有民俗气息的,里面充满了喜庆祥和的味道。
于是我在网络上找到了一个春联网站 www.duiduilian.com/chunlian/ ,里面的内容质量不错。于是,我就写了个爬虫程序去采集数据。
2.1 剖析元素打开网址,浏览器按F12剖析网页。
剖析可见,我们关注的主体内容都在<div class="content_zw"></div>之间,而且一幅对联用<p></p>包裹,高下联用,分割。
这是极其标准的数据爬取的素材案例,或许这便是为了传授教化而设计的。
如果我们要获取春联内容的话,只须要通过网址加载下来html代码,然后取出正文部分,然后通过<p>标签分组,每副春联通过逗号“,”分高下联,末了存入文件就行了。
开干。
2.2 取出正文首先加载网址,取出我们关注的正文。
import requestsimport re# 仿照浏览器发送http要求response = requests.get(url)# 设置编码办法response.encoding='gbk'# 获取全体网页htmlhtml = response.text# 根据标签剖析,从html中获取正文allText = re.findall(r'<div class="content_zw">.?</div>', html, re.S)[0]print(url+"\n allText:"+allText)复制代码
个中值得一讲的便是re是正则表达式的支持库,上面的re.findall便是从html文本中找到所有形状类似于<div class="content_zw">乱七八糟什么内容都行</div>的内容。由于可能会找到多个,但是此处场景只有一个,以是取第一个[0]便是我们想要的。
这样,我们就拿到了如下内容:
<div class="content_zw"><p>春来眼际,喜上眉梢</p><p>春光普照,福泽长临</p><p>春和景明,物阜年丰</p><p>春降大地,福满人间</p><p>春明花艳,民富国强</p>……</div>复制代码
2.3 拆出对联
从目标html文本中,选出对联。
text = "<div class='content_zw'><p>春来眼际,喜上眉梢</p><p>春光普照,福泽长临</p></div>"couplets = re.findall(r'<p>(.?)</p>',text)print(couplets) # ['春来眼际,喜上眉梢', '春光普照,福泽长临']for couplet in couplets: cs = couplet.split(",") print("上联:",cs[0], ",下联:",cs[1]) # 上联: 春来眼际 ,下联: 喜上眉梢 上联: 春光普照 ,下联: 福泽长临复制代码
这里面依然用到了re.findall。这个方法是爬虫程序中很常用的方法。所谓爬取数据,实在便是拿到全量文本,然后撕下来你感兴趣的一段文本。如何来撕,就靠re合营一系列规则来实现。
re.findall(r'<p>(.?)</p>',text)指的是从text中,选取出<p>乱七八糟什么内容都行</p>形状的括号内的内容。这里值得一说的是,它只要()里面的内容。
举个例子:
text = "<p>春来眼际,喜上眉梢</p>"text_r1 = re.findall(r'<p>(.?)</p>',text)[0]print(text_r1) # 春来眼际,喜上眉梢text_r2 = re.findall(r'<p>.?</p>',text)[0]print(text_r2) # <p>春来眼际,喜上眉梢</p>复制代码
看上面的两个列子,就可以理解带不带括号的差异了。
获取到了couplets实在是一个数组['春来眼际,喜上眉梢', '春光普照,福泽长临']。然后,再循环这个数组,通过split(",")拆分出高下联。这样你就有了高下联的春联,然后你就可以为所欲为了。
2.4 还有分页上面只是说了一个url页面。
但是,实际上,有好多并列的页面。
第一个入口页面我们可以手动输进去,但是其他页面你得自动一些了吧。
下面是分页部分的html代码剖析:
我们F12调试可以看到,分页部分和春联内容一样,也在div.content_zw内部,它的整体标签是<div id="pages"></div>包裹的。
<div id="pages"> <a class="a1" href="/chunlian/4zi.html">上一页</a> <span>1</span> <a href="/chunlian/4zi_2.html">2</a> <a href="/chunlian/4zi_3.html">3</a> …… <a href="/chunlian/4zi_8.html">8</a> <a class="a1" href="/chunlian/4zi_2.html">下一页</a></div>复制代码
个中a标签里面的href便是相对路径的url连接,我们考试测验取一下。
# 获取分页干系的网页htmlpages = re.findall(r'<div id="pages">.?</div>', allText, re.S)[0]page_list = re.findall(r'href="/chunlian/(.?)">(.?)<',pages)page_urls = []for page in page_list: if page[1] != '下一页': page_url="https://www.duiduilian.com/chunlian/%s" % page[0] page_urls.append(page_url)# page_urls 便是所有链接复制代码
相信通过之前的解释,这里大多数代码你已经能看明白了。这和获取p标签里的对联很像,差异便是这里面有2个()。我们打印一下匹配出来的page_list:
page_list: [('4zi.html', '上一页'), ('4zi_2.html', '2'), ('4zi_3.html', '3'), ('4zi_4.html', '4'), ('4zi_5.html', '5'), ('4zi_6.html', '6'), ('4zi_7.html', '7'), ('4zi_8.html', '8'), ('4zi_2.html', '下一页')]复制代码
原来, re.findall(r'href="/chunlian/(.?)">(.?)<',pages)意思便是,要取2处地方,分别是……/chunlian/(这个位置1)">(这个位置2)<……。
除了“下一个”按钮之外,其他的<a>链接恰好便是1~8页的完全地址,这样我们就全获取到了。
2.5 全部代码好了,分页也搞定了,那所有链接就有了,每一个链接如何撕下来春联句子也就有了,下面是全部代码。
import requestsimport re def getContent(url): response = requests.get(url) response.encoding='gbk' html = response.text allText = re.findall(r'<div class="content_zw">.?</div>', html, re.S)[0] return allTextdef getPageUrl(allText): pages = re.findall(r'<div id="pages">.?</div>', allText, re.S)[0] page_list = re.findall(r'href="/chunlian/(.?)">(.?)<',pages) page_urls = [] for page in page_list: if page[1] != '下一页': page_url="https://www.duiduilian.com/chunlian/%s" % page[0] print("page_url:",page_url) page_urls.append(page_url) return page_urlsdef do(url, file_name): c_text = getContent(url) pages = getPageUrl(c_text) f = open(file_name,'w') for page_url in pages: page_text = getContent(page_url) page_couplets = re.findall(r'<p>(.?)</p>',page_text) str = '\n'.join(page_couplets)+'\n' f.write(str) f.close() url = 'https://www.duiduilian.com/chunlian/4zi.html'file_name = 'blog4.txt'do(url, file_name)复制代码
我故意省却了注释,由于我想说,实在这个功能只有30行代码。
终极,它把获取到的数据存到名字为blog4.txt文件中了。
这是4字的春联,还有5字的,6字的,7字的,可以如法炮制。
3. 空想和现实看完上面的内容,你可以去用饭了,由于你已经节制了温室大棚里的生存技能。
吃完饭后,我见告你,上面30行代码的实现,实在是空想情形,现实是不可能是这样的。
实际上还有很多非常情形。
比如,下面这个,春联正文的<p>标签里面有我们想要的,也有我们不想要的,都拿过来肯定用不了。
再看下面这个,春联正文里就没有<p>标签,那你想办法吧。
再看下面这个,当分页过多时,涌现了省略号,有些页码的链接就不全了,有些数据就取不到了。
末了,再看下面这个,分页是列表形状的,你还用原来的方法就无法适配了。
是吧,教程和实战还是有差异的。
教程,越干净越好,要用最短的间隔来讲述一个知识点,滋扰项越少越好。
实战,越真实越好,要用最全面的考虑来设计一项功能,非常项越多越好。