用Python模仿名人的风格写一句话

抓取某位名人的演讲内容,通过对演讲内容用词的分析,按照这篇演讲的风格模拟生成一段文字。

整体思路是从网上抓取内容后对格式进行整理,提取文章中的所有单词。然后在统计每个单词后面衔接的单词的频次。例如:I believe I can fly, I believe I can touch the sky. 这句话中,单词I后面出现的单词是believe 2次,can 2次,而can后面出现的单词是fly 1次,touch 1次, 而believe后面出现的单词是I两次。所以,如果用I开头模仿这个风格造一个三个词的句子,很有可能是I can fly或I can touch或I believe I。

用Scrapy抓取http://pythonscraping.com/files/inaugurationSpeech.txt这篇文章,该文是美国第九任总统威廉.亨利.哈里森的就职演说。1840年,威廉.亨利.哈里森在68岁高龄时竞选获胜,哈里森就职那天正遇上寒流,凛冽寒风中,哈里森用了近两个小时宣读他的就职演说。他的演讲加上几位其他官员的讲话,使参加者长时间领略了华盛顿的寒冷。几天之后,这位老人就得了肺炎,在32天后逝去,成为美国第一位在任内去世的总统也是历史上在位时间最短的总统。

创建蜘蛛类并将蜘蛛命名为babyspider6

class MySpider(scrapy.Spider):

    name = 'babyspider6'

重写start_requests方法并传入要抓取的链接:

def start_requests(self):
        url = 'http://pythonscraping.com/files/inaugurationSpeech.txt'

        yield scrapy.Request(url, callback=self.parse)

在重写parse方法之前先写一些辅助性的方法。

还用上面的例子来说,对于I believe I can fly, I believe I can touch the sky. 这件话在拆分词和统计衔接词的时候会使用字典来组织内容:

{'I':{'believe':2,'can':2},
 'believe':{'I':2},
 'can':{'fly':1,'touch':1},
 ...
}

所以写一个buildWordDict方法来生成这样的字典:

def buildWordDict(self, text):
        text = text.replace('\n', '')
        text = text.replace('"', '')
        punc = [',', '.', ';', ':']
        for x in punc:
            text = text.replace(x, ' ' + x + ' ')
        words = text.split()
        words = [word for word in words if word != '']

        wordsDict = {}

        for x in range(1, len(words)):
            if words[x - 1] not in wordsDict:
                wordsDict[words[x - 1]] = {}
            if words[x] not in wordsDict[words[x - 1]]:
                wordsDict[words[x - 1]][words[x]] = 0
            wordsDict[words[x - 1]][words[x]] += 1

        return wordsDict

因为较长的一句话中也会包含标点符号进行断句,所以代码中对标点符号都进行了处理,在标点符号的前后加上空格,方便使用split函数对全文进行拆分。

在获得了这样的单词后,我们就要进行单词的筛选。筛选的方案有很多种,但总的原则是应该让频次高的单词更有可能被选中。这里采用的方式是将频次作为分数(权重),然后利用分数进行筛选。

继续用上面的例子:I后面的衔接单词的总分数是4分,然后利用python的randint生成一个1~4的随机数value,依次用value减去衔接词的分数,当value的值<=0的时候,就将这个衔接词返回。如果生成的value为1或2则返回believe,如果生成的value为3或4则返回can。

def wordlistSum(self, wordlist):
        sum = 0
        for k, v in wordlist.items():
            sum += v
        return sum

def getRandomWord(self, wordList):
        value = randint(1, self.wordlistSum(wordList))
        for k, v in wordList.items():
            value -= v
            if value <= 0:
                return k

现在可以重写parse方法接收演讲正文并进行处理生成一句话:

    def parse(self, response):
        text = response.text
        wordsDict = self.buildWordDict(text)
        length = int(getattr(self, 'len', 20))
        chain = ''
        currentWord = 'I'
        for x in range(length):
            chain += currentWord + ' '
            if currentWord == '.': break
            currentWord = self.getRandomWord(wordsDict[currentWord])
        with open('speech.txt', 'w') as f:
            f.write(chain)

我们使用单词I作为一句话的开头,默认句子中单词的个数为20个,可以通过Scrapy的命令行提供不同的单词个数。拼句子的时候如果发现了句号或者单词个数达到了length,则停止句子的拼接。并将拼接的结果写入speech.txt中保存。

scrapy crawl babyspider6 -a len=30

得到的句子是:

I know the security of the public finances ; and manly examination of power of their engagements into which thousands of that patriot from whose coming was created . 

百度翻译一下:我知道公共财政的安全性,也很有男子气概地检查了他们交战的力量,成千上万的爱国者从中诞生。

 

你可能感兴趣的:(python)