使用 Python 构建虚拟助手 | 自动执行任务

2025-05-28

使用 Python 构建虚拟助手 | 自动执行任务

这篇文章与OnePublish交叉发布

DEV Network怎么样?

带有视频教程的 YouTube 频道 - Reverse Python Youtube

在本实验中,我们将使用 Python 构建《星际穿越》电影中的 TARS 演示程序。TARS 可以帮助您自动执行各种任务,例如在 YouTube 上搜索并播放视频、发送电子邮件、打开网站、在维基百科中搜索并阅读资料、显示您所在国家/地区的天气预报、问候语等等。通过构建 TARS,您将提升 Python 知识并学习许多实用的库/工具。我会将源代码推送到我的 git 代码库,欢迎您随时贡献代码,改进 TARS 的功能。

TARS

让我们从创建虚拟环境和构建 TARS 的基本音频系统开始。

mkdir TARS
cd TARS
virtualenv venv
Enter fullscreen mode Exit fullscreen mode

要激活 venv,请运行以下命令

. venv/bin/activate
Enter fullscreen mode Exit fullscreen mode

什么是虚拟环境?

一旦激活了 venv,我们需要通过以下命令安装主要库:

pip3 install gTTS
pip3 install SpeechRecognition
pip3 install PyAudio
pip3 install pygame
Enter fullscreen mode Exit fullscreen mode

gTTS(Google 文本转语音)是一个 Python 库和 CLI 工具,用于与 Google 翻译的文本转语音 API 交互。该模块有助于将字符串文本转换为口语文本,并可保存为 .mp3 文件。

语音识别是家庭自动化、人工智能等众多应用中的重要功能。语音识别需要音频输入,而 SpeechRecognition 可以非常轻松地检索这些输入。无需从头编写脚本来访问麦克风并处理音频文件,SpeechRecognition 只需几分钟即可让您轻松上手。

要使用 SpeechRecognizer 访问麦克风,您必须安装PyAudio

Pygame是一套跨平台的 Python 模块,用于编写视频游戏。它包含一些专为 Python 编程语言设计的计算机图形和声音库。

现在,我们来构建TARS的语音系统:

from gtts import gTTS
import speech_recognition as sr
from pygame import mixer

def talk(audio):
    print(audio)
    for line in audio.splitlines():
        text_to_speech = gTTS(text=audio, lang='en-uk')
        text_to_speech.save('audio.mp3')
        mixer.init()
        mixer.music.load("audio.mp3")
        mixer.music.play()
Enter fullscreen mode Exit fullscreen mode

如您所见,我们将音频作为参数传递,让 TARS 说话。例如,talk('Hey I am TARS! How can I help you?')程序将借助 splitlines() 方法循环播放这些行。此方法用于在行边界处分割行。更多信息,请查看splitlines()。然后,gTTS 将处理所有这些文本并将其转换为语音。text 参数定义要读取的文本,lang 定义读取文本的语言(IETF 语言标签)。循环完成后,save() 方法将结果写入文件。

pygame.mixer是一个用于加载和播放声音的模块,使用前必须初始化。

好了!现在,让我们创建一个监听命令的函数。

def myCommand():
    #Initialize the recognizer 
    r = sr.Recognizer()

    with sr.Microphone() as source:
        print('TARS is Ready...')
        r.pause_threshold = 1
        #wait for a second to let the recognizer adjust the  
        #energy threshold based on the surrounding noise level 
        r.adjust_for_ambient_noise(source, duration=1)
        #listens for the user's input
        audio = r.listen(source)

    try:
        command = r.recognize_google(audio).lower()
        print('You said: ' + command + '\n')

    #loop back to continue to listen for commands if unrecognizable speech is received
    except sr.UnknownValueError:
        print('Your last command couldn\'t be heard')
        command = myCommand();

    return command
Enter fullscreen mode Exit fullscreen mode

在这个函数中,我们使用了 SpeechRecognition 库。它封装了多种常用的语音 API,因此非常灵活。其中之一——Google Web Speech API——支持默认的 API 密钥,该密钥硬编码在 SpeechRecognition 库中。这意味着您无需注册任何服务即可开始使用。

为了能够使用语音识别处理您自己的声音,您需要 PyAudio 软件包。与音频文件的识别器一样,我们需要麦克风来处理实时语音数据。

您可以使用 with 代码块中 Recognizer 类的 listen() 方法捕获来自麦克风的输入。此方法将音频源作为其第一个参数,并记录来自音频源的输入,直到检测到静音为止。

尝试在安静的地方(背景噪音较少)说出您的命令,否则 TARS 可能会造成混淆。

看看《Python 语音识别终极指南》

import random

def tars(command):
    errors=[
        "I don\'t know what you mean!",
        "Excuse me?",
        "Can you repeat it please?",
    ]

    if 'Hello' in command:
        talk('Hello! I am TARS. How can I help you?')

    else:
        error = random.choice(errors)
        talk(error)


talk('TARS is ready!')


while True:
    assistant(myCommand())
Enter fullscreen mode Exit fullscreen mode

运行程序后,TARS 会先跟你对话,说“TARS 已准备就绪!”,然后持续监听你的指令,直到你停止程序。先说“你好” :)

当TARS没有收到命令时我们会用随机的句子来处理错误。

以下是主要结构的完整代码:

from gtts import gTTS
import speech_recognition as sr
from pygame import mixer
import random
def talk(audio):
    print(audio)
    for line in audio.splitlines():
        text_to_speech = gTTS(text=audio, lang='en-uk')
        text_to_speech.save('audio.mp3')
        mixer.init()
        mixer.music.load("audio.mp3")
        mixer.music.play()

def myCommand():
    #Initialize the recognizer
    #The primary purpose of a Recognizer instance is, of course, to recognize speech. 
    r = sr.Recognizer()

    with sr.Microphone() as source:
        print('TARS is Ready...')
        r.pause_threshold = 2
        #wait for a second to let the recognizer adjust the  
        #energy threshold based on the surrounding noise level 
        r.adjust_for_ambient_noise(source, duration=1)
        #listens for the user's input
        audio = r.listen(source)

    try:
        command = r.recognize_google(audio).lower()
        print('You said: ' + command + '\n')

    #loop back to continue to listen for commands if unrecognizable speech is received
    except sr.UnknownValueError:
        print('Your last command couldn\'t be heard')
        command = myCommand();
    return command

def tars(command):
    errors=[
        "I don't know what you mean",
        "Did you mean astronaut?",
        "Can you repeat it please?",
    ]
    if 'hello' in command:
        talk('Hello! I am TARS. How can I help you?')
    else:
        error = random.choice(errors)
        talk(error)


talk('TARS is ready!')

#loop to continue executing multiple commands
while True:
    tars(myCommand())
Enter fullscreen mode Exit fullscreen mode

那么...AI 难道不就是一堆 IF 语句吗?

人工智能

如果你谈论的是“真正的”人工智能,那么它不仅仅是 If 语句。人工智能的发展在历史上分为两个领域:符号人工智能和机器学习。

符号人工智能(Symbolic AI)是指使用 if-else 类型逻辑来设计人工智能系统的领域。程序员会尝试定义系统可能处理的所有场景。直到 20 世纪 70 年代末,这种形式一直是人工智能系统开发的主流。该领域的专家们曾强烈主张,机器学习永远不会流行,人工智能只能以这种方式编写。

现在我们知道,在智能系统中考虑所有可能的情况极其不切实际,因此我们采用机器学习来代替。机器学习利用统计数据来寻找和定义数据中的模式,从而使机器能够学习并改进其设计要执行的任务。这显著提高了灵活性。

我们只是用一堆 IF 语句来理解 AI 的基础知识。但稍后我们会实现一些很酷的机器学习算法。

我希望你到目前为止学到了新的东西,现在是时候教 TARS 如何实现自动化了。

打开 Google 并搜索某些内容

我们将导入Python 中的webbrowser模块,它提供了一个显示基于 Web 的文档的界面。

当我们说出命令时,TARS 必须通过匹配来检测这些命令是否可用。Python 有一个名为re的内置包,可用于处理正则表达式。

import re
import webbrowser

if 'open google' in command:
        #matching command to check it is available
        reg_ex = re.search('open google (.*)', command)
        url = 'https://www.google.com/'
        if reg_ex:
            subgoogle = reg_ex.group(1)
            url = url + 'r/' + subreddit
        webbrowser.open(url)
        print('Done!')
Enter fullscreen mode Exit fullscreen mode

re.search() 方法接受一个正则表达式和一个字符串,并在该字符串中搜索该模式。如果搜索成功,search() 将返回一个匹配对象,否则返回 None。因此,搜索之后通常会紧接着一个 if 语句来测试搜索是否成功。

代码 reg_ex = re.search('open google (.*)', command) 将搜索结果存储在名为“reg_ex”的变量中。然后,if 语句测试匹配结果——如果匹配结果为真,则搜索成功,group() 为匹配的文本。否则,如果匹配结果为假(更确切地说是 None),则搜索失败,没有匹配的文本。reg_ex.group (1)中的 1表示第一个带括号的子组。

你甚至可以安装Selenium来通过 TARS 在 Google 上进行搜索。要安装 Selenium,请运行以下命令:

pip3 install selenium
Enter fullscreen mode Exit fullscreen mode

Selenium WebDriver 是一组开源 API,用于自动化 Web 应用程序的测试。此工具用于自动化 Web 应用程序测试,以验证其是否按预期运行。它支持多种浏览器,例如 Safari、Firefox、IE 和 Chrome。

你可以搜索如何在 Python 中使用 Selenium,网上有很多资源,而且很容易学习。让我们把这个功能添加到 TARS 中吧。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

    if 'open google and search' in command:
        reg_ex = re.search('open google and search (.*)', command)
        search_for = command.split("search",1)[1]
        url = 'https://www.google.com/'
        if reg_ex:
            subgoogle = reg_ex.group(1)
            url = url + 'r/' + subgoogle
        talk('Okay!')
        driver = webdriver.Firefox(executable_path='/path/to/geckodriver') #depends which web browser you are using
        driver.get('http://www.google.com')
        search = driver.find_element_by_name('q') # finds search
        search.send_keys(str(search_for)) #sends search keys 
        search.send_keys(Keys.RETURN) #hits enter
Enter fullscreen mode Exit fullscreen mode

TARS 会处理“打开 Google 搜索”命令后的字符串,并将所有单词作为搜索键。我使用的是 Firefox,因此安装了 geckodriver。如果您使用的是 Chrome,请查看以下 StackOverflow 问题。

81

我正在开始学习《自动化无聊内容》这本书,并尝试通过 Python 打开 Chrome 浏览器。我已经安装了 Selenium 和

我尝试运行这个文件:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

browser = webdriver.Chrome()
browser.get('https://automatetheboringstuff.com')

但因为……

发送电子邮件

我们将导入smtplib来使用 Python 发送电子邮件。SMTP 代表简单邮件传输协议,它可用于与邮件服务器通信以发送邮件。

  import smtplib

  elif 'email' or 'gmail' in command:
        talk('What is the subject?')
        time.sleep(3)
        subject = myCommand()
        talk('What should I say?')
        time.sleep(3)
        message = myCommand()
        content = 'Subject: {}\n\n{}'.format(subject, message)

        #init gmail SMTP
        mail = smtplib.SMTP('smtp.gmail.com', 587)

        #identify to server
        mail.ehlo()

        #encrypt session
        mail.starttls()

        #login
        mail.login('your_gmail', 'your_gmail_password')

        #send message
        mail.sendmail('FROM', 'TO', content)

        #end mail connection
        mail.close()

        talk('Email sent.')
Enter fullscreen mode Exit fullscreen mode

请注意,简而言之,谷歌不允许您通过 smtplib 登录,因为它将这种登录标记为“不太安全”,所以您要做的就是在登录到您的谷歌帐户时转到此链接,并允许访问。

使能够

谷歌

还是无法正常工作?请查看此 StackOverflow 问题

169

我正在尝试通过 Gmail 用 Python 发送一封电子邮件。这是我的代码:

import smtplib
fromaddr = '......................'  
toaddrs  = '......................'  
msg = 'Spam email Test'  
      
username = '.......'  
password = '.......'

server = smtplib.SMTP('smtp.gmail.com', 587)  
server.ehlo()
server.starttls()
server.login(username, password)  
server.sendmail(fromaddr, toaddrs, msg)  
server.quit()

我收到错误:

抓取数据

到目前为止,我们做得很棒!TARS 可以发送邮件,还能在 Google 上搜索任何你想搜索的内容。现在,让我们实现更复杂的功能,让 TARS 抓取一些维基百科数据并帮我们读取。

Beautiful Soup是一个用于从 HTML 和 XML 文件中提取数据的 Python 库。它可以与您常用的解析器配合使用,提供惯用的方式导航、搜索和修改解析树。它通常可以为程序员节省数小时甚至数天的工作时间。在终端中运行以下命令安装 beautifulsoup:

pip install beautifulsoup4
Enter fullscreen mode Exit fullscreen mode

我们还需要用Python 的请求库来发起 HTTP 请求。它将发起请求的复杂性抽象到一个简洁美观的 API 背后,这样你就可以专注于与服务交互以及在应用程序中使用数据。好了!我们来看代码:

import bs4
import requests

elif 'wikipedia' in command:
        reg_ex = re.search('search in wikipedia (.+)', command)
        if reg_ex: 
            query = command.split()
            response = requests.get("https://en.wikipedia.org/wiki/" + query[3])

            if response is not None:
                html = bs4.BeautifulSoup(response.text, 'html.parser')
                title = html.select("#firstHeading")[0].text
                paragraphs = html.select("p")
                for para in paragraphs:
                    print (para.text)


                intro = '\n'.join([ para.text for para in paragraphs[0:5]])
                print (intro)
                mp3name = 'speech.mp3'
                language = 'en'
                myobj = gTTS(text=intro, lang=language, slow=False)   
                myobj.save(mp3name)
                mixer.init()
                mixer.music.load("speech.mp3")
                mixer.music.play()
    elif 'stop' in command:
        mixer.music.stop()

Enter fullscreen mode Exit fullscreen mode

“在维基百科火星搜索”,TARS 会以“火星”作为关键词在维基百科中进行搜索。如果您在维基百科上搜索,您会看到 URL 类似于 https://en.wikipedia.org/wiki/Keyword,因此我们发送了包含关键词(搜索内容)的 get 请求来访问数据。请求成功后,beautifulsoup 将解析维基百科中的内容。join() 方法是一个字符串方法,返回一个字符串,其中序列元素由 str 分隔符连接,我们用它来分隔段落。您已经熟悉 gTTS 和 mixer,所以我将略过这部分。

TARS 会在控制台上显示抓取到的数据并开始为您读取。

在 YouTube 上搜索视频并播放

这个函数和用 Google 搜索类似,但这次最好使用urllib。主要目的是学习 Python 的新知识,所以我不想在这个函数中包含 Selenium。代码如下:

import urllib.request #used to make requests
import urllib.parse #used to parse values into the url

 elif 'youtube' in command:
        talk('Ok!')
        reg_ex = re.search('youtube (.+)', command)
        if reg_ex:
            domain = command.split("youtube",1)[1] 
            query_string = urllib.parse.urlencode({"search_query" : domain})
            html_content = urllib.request.urlopen("http://www.youtube.com/results?" + query_string) 
            search_results = re.findall(r'href=\"\/watch\?v=(.{11})', html_content.read().decode()) # finds all links in search result
            webbrowser.open("http://www.youtube.com/watch?v={}".format(search_results[0]))
            pass
Enter fullscreen mode Exit fullscreen mode

Python 3 中的urllib模块允许你通过程序访问网站。这为你的程序打开了如同互联网为你打开的大门一样多的大门。Python 3 中的 urllib 与 Python 2 中的 urllib2 略有不同,但基本相同。通过 urllib,你可以访问网站、下载数据、解析数据、修改头部信息,以及执行任何你需要的 GET 和 POST 请求。

查看本教程了解有关 urllib 的更多信息

搜索关键字必须先编码才能解析为 url。如果您在 YouTube 上搜索某些内容,您会在 http://www.youtube.com/results? 后看到编码的搜索关键字。编码这些搜索关键字后,程序即可成功访问搜索结果。表达式re.findall()将字符串中所有不重叠的模式匹配作为字符串列表返回。YouTube 上的每个视频都有自己的 11 个字符 ID(https://www.youtube.com/watch?v=gEPmA3USJdI ), re.findall () 将在解码的 html_content(在搜索结果页面中)中找到所有匹配项。decode ()用于从一种编码方案转换为所需的编码方案,其中参数字符串被编码。这与编码相反。它接受编码字符串的编码以对其进行解码并返回原始字符串。最后,它播放搜索结果中的第一个视频,因为通常第一个视频与搜索关键字最接近。

完整代码:

from gtts import gTTS
import speech_recognition as sr
import re
import time
import webbrowser
import random
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import smtplib
import requests
from pygame import mixer
import urllib.request
import urllib.parse
import bs4


def talk(audio):
    "speaks audio passed as argument"

    print(audio)
    for line in audio.splitlines():
        text_to_speech = gTTS(text=audio, lang='en-uk')
        text_to_speech.save('audio.mp3')
        mixer.init()
        mixer.music.load("audio.mp3")
        mixer.music.play()


def myCommand():
    "listens for commands"
    #Initialize the recognizer
    #The primary purpose of a Recognizer instance is, of course, to recognize speech. 
    r = sr.Recognizer()

    with sr.Microphone() as source:
        print('TARS is Ready...')
        r.pause_threshold = 1
        #wait for a second to let the recognizer adjust the  
        #energy threshold based on the surrounding noise level 
        r.adjust_for_ambient_noise(source, duration=1)
        #listens for the user's input
        audio = r.listen(source)
        print('analyzing...')

    try:
        command = r.recognize_google(audio).lower()
        print('You said: ' + command + '\n')
        time.sleep(2)

    #loop back to continue to listen for commands if unrecognizable speech is received
    except sr.UnknownValueError:
        print('Your last command couldn\'t be heard')
        command = myCommand();

    return command


def tars(command):
    errors=[
        "I don't know what you mean",
        "Excuse me?",
        "Can you repeat it please?",
    ]
    "if statements for executing commands"

    # Search on Google
    if 'open google and search' in command:
        reg_ex = re.search('open google and search (.*)', command)
        search_for = command.split("search",1)[1] 
        print(search_for)
        url = 'https://www.google.com/'
        if reg_ex:
            subgoogle = reg_ex.group(1)
            url = url + 'r/' + subgoogle
        talk('Okay!')
        driver = webdriver.Firefox(executable_path='/home/coderasha/Desktop/geckodriver')
        driver.get('http://www.google.com')
        search = driver.find_element_by_name('q')
        search.send_keys(str(search_for))
        search.send_keys(Keys.RETURN) # hit return after you enter search text

    #Send Email
    elif 'email' in command:
        talk('What is the subject?')
        time.sleep(3)
        subject = myCommand()
        talk('What should I say?')
        message = myCommand()
        content = 'Subject: {}\n\n{}'.format(subject, message)

        #init gmail SMTP
        mail = smtplib.SMTP('smtp.gmail.com', 587)

        #identify to server
        mail.ehlo()

        #encrypt session
        mail.starttls()

        #login
        mail.login('your_mail', 'your_mail_password')

        #send message
        mail.sendmail('FROM', 'TO', content)

        #end mail connection
        mail.close()

        talk('Email sent.')

    # search in wikipedia (e.g. Can you search in wikipedia apples)
    elif 'wikipedia' in command:
        reg_ex = re.search('wikipedia (.+)', command)
        if reg_ex: 
            query = command.split("wikipedia",1)[1] 
            response = requests.get("https://en.wikipedia.org/wiki/" + query)
            if response is not None:
                html = bs4.BeautifulSoup(response.text, 'html.parser')
                title = html.select("#firstHeading")[0].text
                paragraphs = html.select("p")
                for para in paragraphs:
                    print (para.text)
                intro = '\n'.join([ para.text for para in paragraphs[0:3]])
                print (intro)
                mp3name = 'speech.mp3'
                language = 'en'
                myobj = gTTS(text=intro, lang=language, slow=False)   
                myobj.save(mp3name)
                mixer.init()
                mixer.music.load("speech.mp3")
               while mixer.music.play()
    elif 'stop' in command:
        mixer.music.stop()

    # Search videos on Youtube and play (e.g. Search in youtube believer)
    elif 'youtube' in command:
        talk('Ok!')
        reg_ex = re.search('youtube (.+)', command)
        if reg_ex:
            domain = command.split("youtube",1)[1] 
            query_string = urllib.parse.urlencode({"search_query" : domain})
            html_content = urllib.request.urlopen("http://www.youtube.com/results?" + query_string)
            search_results = re.findall(r'href=\"\/watch\?v=(.{11})', html_content.read().decode())
            #print("http://www.youtube.com/watch?v=" + search_results[0])
            webbrowser.open("http://www.youtube.com/watch?v={}".format(search_results[0]))
            pass



    elif 'hello' in command:
        talk('Hello! I am TARS. How can I help you?')
        time.sleep(3)
    elif 'who are you' in command:
        talk('I am one of four former U.S. Marine Corps tactical robots')
        time.sleep(3)
    else:
        error = random.choice(errors)
        talk(error)
        time.sleep(3)


talk('TARS activated!')

#loop to continue executing multiple commands
while True:
    time.sleep(4)
    tars(myCommand())
Enter fullscreen mode Exit fullscreen mode

太棒了!我们刚刚创建了 TARS 的演示版本,希望您能从本次实验中学到很多东西。欢迎在GitHub上为这个项目做出贡献,TARS 会持续改进。

各位开发者们,下篇文章见!保持联系!🚀

Instagram
Twitter请给我买杯咖啡
来支持我

文章来源:https://dev.to/thedevtimeline/build-virtual-assistant-with-python-automate-tasks-46a6
PREV
使用 Python 比较文档相似度 | NLP Resemblance 对语料库执行相似性查询 print(document_number, document_similarity) 构建索引
NEXT
Python 高级自动化技巧 | Selenium