RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1163422
Accepted
gil9red
gil9red
Asked:2020-08-08 02:53:37 +0000 UTC2020-08-08 02:53:37 +0000 UTC 2020-08-08 02:53:37 +0000 UTC

旧的 youtube 视频按需搜索脚本坏了

  • 772

我有这样一个用于在 YouTube 上搜索的脚本(我在电报机器人中使用它):

import urllib
import re
import random

link = urllib.parse.urlencode({"search_query": msg})
content = urllib.request.urlopen("https://www.youtube.com/results?" + link)
search_results = re.findall('href=\"\/watch\?v=(.*?)\"', content.read().decode())
if len(search_results) > 0:
    search_results = search_results[0:9:1]
    choice_f = random.choice(search_results)
    yt_link = "https://www.youtube.com/watch?v="+choice_f

他不整洁,他通过正则表达式工作,总的来说,他不是我的:)

现在它没有返回任何东西,我想弄清楚发生了什么变化以及如何修复它。

python
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    gil9red
    2020-08-08T02:53:37Z2020-08-08T02:53:37Z

    简而言之(我想要更多详细信息,请参见下文),然后该脚本可以正常工作,因为搜索结果是在对请求的响应中以 HTML 格式返回的。

    现在搜索结果将在javascript中,需要对其进行提取和处理。

    现成的解决方案(2020 年 10 月 28 日更新,支持var ytInitialData):

    import json
    from typing import List, Tuple, Optional
    import re
    
    # pip install dpath
    import dpath.util
    
    import requests
    
    
    USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0'
    PATTERNS = [
        re.compile(r'window\["ytInitialData"\] = (\{.+?\});'),
        re.compile(r'var ytInitialData = (\{.+?\});'),
    ]
    
    session = requests.Session()
    session.headers['User-Agent'] = USER_AGENT
    
    
    def get_ytInitialData(url: str) -> Optional[dict]:
        rs = session.get(url)
    
        for pattern in PATTERNS:
            m = pattern.search(rs.text)
            if m:
                data_str = m.group(1)
                return json.loads(data_str)
    
    
    def search_youtube(text_or_url: str) -> List[Tuple[str, str]]:
        if text_or_url.startswith('http'):
            url = text_or_url
        else:
            text = text_or_url
            url = f'https://www.youtube.com/results?search_query={text}'
    
        items = []
    
        data = get_ytInitialData(url)
        if not data:
            return items
    
        videos = dpath.util.values(data, '**/videoRenderer')
        if not videos:
            videos = dpath.util.values(data, '**/playlistVideoRenderer')
    
        for video in videos:
            if 'videoId' not in video:
                continue
    
            url = 'https://www.youtube.com/watch?v=' + video['videoId']
            try:
                title = dpath.util.get(video, 'title/runs/0/text')
            except KeyError:
                title = dpath.util.get(video, 'title/simpleText')
    
            items.append((url, title))
    
        return items
    

    现在更多

    让我们从一开始就尝试处理解析。下面会有很多截图!

    首先,我们看一下搜索机制:

    在此处输入图像描述

    在此处输入图像描述

    事实证明,对于搜索,您需要以这种形式格式化 URL:

    https://www.youtube.com/results?search_query={文本}

    这里没有任何改变。

    通过浏览器检查器检查结构

    我们戳鼠标右键并选择Inspect Element:

    在此处输入图像描述

    一个面板将像这样打开:

    在此处输入图像描述

    我们研究并寻找视频的链接:

    在此处输入图像描述

    让我们尝试解析:

    例如,让我们查找视频标签,例如ytd-video-renderer:

    from bs4 import BeautifulSoup
    import requests
    
    rs = requests.get('https://www.youtube.com/results?search_query=slipknot')
    root = BeautifulSoup(rs.content, 'html.parser')
    print(len(root.select('ytd-video-renderer')))
    # 0
    

    没有什么...

    如果您寻找在检查员中看到的链接?

    import requests
    
    rs = requests.get('https://www.youtube.com/results?search_query=slipknot')
    print(rs.text.count('/watch?v=5abamRO41fE'))
    # 4
    

    有趣...原来有一个链接,但它在错误的标签中。

    让我们看看响应搜索请求的结果:

    • 你可以通过浏览器,通过鼠标右键选择View Page Source
    • 或脚本:
      import requests
      rs = requests.get('https://www.youtube.com/results?search_query=slipknot')
      with open('rs.html', 'wb') as f:
          f.write(rs.content)
      

    未找到标签ytd-video-renderer...

    在此处输入图像描述

    找到ytd-video-renderer了,但它是在javascript中的

    在此处输入图像描述

    А что насчет ссылки? Тоже в javascript (у меня сломался поиск в Page Source, поэтому показываю в Notepad++): 在此处输入图像描述

    Получается, данные с поиском находятся в объекте, находящимся в window["ytInitialData"]:

    在此处输入图像描述

    Изучим window["ytInitialData"]

    Как видим из структуры, видео находятся в объектах videoRenderer

    在此处输入图像描述

    Теперь попробуем вытащить значение из window["ytInitialData"] и обработать его.

    Для вытаскивания используем регулярное выражение, а для парсинга модуль json.

    Как видим, данные успешно вытаскиваются, парсятся и обрабатываются:

    import json
    import re
    import requests
    PATTERN = re.compile(r'window\["ytInitialData"\] = (\{.+?\});')
    
    rs = requests.get('https://www.youtube.com/results?search_query=slipknot')
    
    m = re.search(r'window\["ytInitialData"\] = (\{.+?\});', rs.text)
    data_str = m.group(1)
    print(data_str)
    # {"responseContext":{"serviceTrackingParams":[{"service":"GUIDED_HELP","params":[{"key":"context","va ...
    
    data = json.loads(data_str)
    print(data['contents']['twoColumnSearchResultsRenderer']['primaryContents']['sectionListRenderer']['contents'][0]['itemSectionRenderer']['contents'][2]['videoRenderer'])
    # {'videoId': '5abamRO41fE', 'thumbnail': {'thumbnails': [{'url': ...
    

    Для удобства работы с словарем, я воспользуюсь модулем dpath.util, например так можно вытащить значения всех объектов с ключом videoRenderer:

    import dpath.util
    
    ...
    
    result = dpath.util.values(data, '**/videoRenderer')
    print(len(result))
    # 39
    

    Это все. Надеюсь, это было полезно 😄

    • 24

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5