【问题标题】:Youtube search command for discord.pydiscord.py 的 Youtube 搜索命令
【发布时间】:2021-10-04 08:57:22
【问题描述】:

简单。我正在使用 python 为不和谐创建一个 youtube 搜索命令 这是代码:

async def youtube(ctx, *, search):
    query_string = urllib.parse.urlencode({
        'search_query': search
    })
    htm_content = urllib.request.urlopen(
        'http://www.youtube.com/results?' + query_string
    )
    search_results = re.findall('href=\"\\/watch\\?v=(.{11})', htm_content.read().decode())
    await ctx.send('http://www.youtube.com/watch?v=' + search_results[0])

我遇到的错误是这样的:

Ignoring exception in command youtube:
Traceback (most recent call last):
  File "C:\Users\Ryzen\AppData\Roaming\Python\Python37\site-packages\discord\ext\commands\core.py", line 83, in wrapped
    ret = await coro(*args, **kwargs)
  File "C:\Users\Ryzen\Desktop\ae\bot\bot 2.0\bot.py", line 738, in youtube
    await ctx.send('http://www.youtube.com/watch?v=' + search_results[0])
IndexError: list index out of range

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Ryzen\AppData\Roaming\Python\Python37\site-packages\discord\ext\commands\bot.py", line 892, in invoke
    await ctx.command.invoke(ctx)
  File "C:\Users\Ryzen\AppData\Roaming\Python\Python37\site-packages\discord\ext\commands\core.py", line 797, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "C:\Users\Ryzen\AppData\Roaming\Python\Python37\site-packages\discord\ext\commands\core.py", line 92, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: IndexError: list index out of range

谢谢

【问题讨论】:

  • ...m/watch?v=' + search_results[0] 可能列表为空且没有 0 索引。?
  • 尼梅什卡是正确的。最重要的是,您正在使用 asyncio,因此您应该使用 aiohttp

标签: python discord discord.py


【解决方案1】:

Nimeshka 是正确的,无论您使用什么来填充 search_results 列表都找不到任何东西。

您可以做一些事情来帮助调试。首先,尝试将htm_content.read().decode() 的内容捕获到一个文件中,看看你得到了什么。很有可能会为您提供验证码、错误或其他您无法使用的内容,因为您没有在请求中发送用户代理。

假设您确实获得了所需的 DOM 响应,在文件中保存一份副本可以帮助您更准确地编写正则表达式。此外,使用 regexr 或 regex101 等在线工具进行测试/调试将提供更多帮助。然后使用r"strings" 意味着您可以直接复制正则表达式,而无需复制每个反斜杠。

BASE = "https://youtube.com/results"

async def youtube(ctx, *, search):
    p = {"search_query": search}
    # Spoof a user agent header or the request will immediately fail
    h = {"User-Agent": "Mozilla/5.0"}
    async with aiohttp.ClientSession() as client:
        async with client.get(BASE, params=p, headers=h) as resp:
            dom = await resp.text()
            # open("debug.html", "w").write(dom)
    found = re.findall(r'href"\/watch\?v=([a-zA-Z0-9_-]{11})', dom)
    return f"https://youtu.be/{found[0]}"

最后一句警告,Google 倾向于提供广告而不是排名靠前的结果,因此请记住您的正则表达式实际上返回的是什么;)


或者,我建议使用Google's APIs 建立一个新的开发者项目,因为这将允许您一起跳过网络抓取部分并改用 API 客户端。为google-api-python-client 使用 pip 安装:

from googleapiclient.discovery import build

def get_service():
    # Get developer key from "credentials" tab of api dashboard
    return build("youtube", "v3", developerKey="key")

def search(term, channel):
    service = get_service()
    resp = service.search().list(
        part="id",
        q=term,
        # safeSearch="none" if channel.is_nsfw() else "moderate",
        videoDimension="2d",
    ).execute()
    return resp["items"][0]["id"]["videoId"]

API documentation

【讨论】:

    【解决方案2】:

    我修复了它,将正则表达式行更改为:

    re.findall( r"watch\?v=(\S{11})", html_content.read().decode())
    

    在那之后,它对我有用

    【讨论】:

      【解决方案3】:

      让我们来看看这部分:

      search_results = re.findall('href=\"\\/watch\\?v=(.{11})', htm_content.read().decode())
      await ctx.send('http://www.youtube.com/watch?v=' + search_results[0])
      

      我解决了这个问题,为 search_content 创建一个变量以查看所有 html 页面。

      search_content= html_content.read().decode()
      

      然后我尝试在html内容中找到这个模式

      search_results = re.findall(r'\/watch\?v=\w+', search_content)
      

      现在您的机器人可以将第一个结果发送到 discord 服务器。

      此模式找到\/watch\?v= 部分,然后捕获\w+ 的下一个字符。在这个字符之后有一个 ' 所以re.findall 进程会中断捕获


      这里是完整的代码:

      @bot.command()
      async def youtube(ctx, *, search):
          query_string = parse.urlencode({'search_query': search})
          html_content = request.urlopen('http://www.youtube.com/results?' + query_string)
          search_content= html_content.read().decode()
          search_results = re.findall(r'\/watch\?v=\w+', search_content)
          #print(search_results)
          await ctx.send('https://www.youtube.com' + search_results[0])
      

      我发现了一个非常有趣的页面,您可以在其中调试正则表达式并在文本中查找模式。这个工具帮我解决了这个问题:regex101.com

      希望这篇文章对你有帮助

      【讨论】:

        【解决方案4】:

        您提供的代码几乎完全正确,有两件事需要更改 parse.urlencode 和 request.urlopen。 首先要让这个工作,你需要安装 urllib 所以进入 cmd 并安装它:

        pip 安装 urllib

        那么你需要导入 urllib 来做:

        导入 urllib.parse

        那么你还需要导入 urlencode 所以输入:

        从 urllib.parse 导入 urlencode

        还要安装和导入解析,所以转到 cmd 并执行:

        pip 安装解析

        然后将其导入您的代码中

        导入解析

        当您安装和导入这些代码时,您可以复制/粘贴此代码,它应该适合您:

            @client.command(aliases=['youtube','yt'])
        async def _youtube(ctx, *, search):
            author=ctx.message.author
            guild=ctx.guild
            query_string = urllib.parse.urlencode({'search_query': search})
            html_content = urllib.request.urlopen('http://www.youtube.com/results?' + query_string)
            search_content= html_content.read().decode()
            search_results = re.findall(r'\/watch\?v=\w+', search_content)
            #print(search_results)
            await ctx.send(f'{author.mention} Here is the search result:\n https://www.youtube.com' + search_results[0])
        

        【讨论】:

          猜你喜欢
          • 2021-03-26
          • 2021-08-28
          • 2021-01-22
          • 2021-03-30
          • 2021-05-17
          • 2021-01-15
          • 2022-12-04
          • 2023-02-25
          • 2012-02-09
          相关资源
          最近更新 更多