【问题标题】:How do I extract link from website if after parsing in Python, the download link is not extracted. And also the href attribute is javascript:void(0)如果在 Python 中解析后没有提取下载链接,如何从网站中提取链接。而且 href 属性是 javascript:void(0)
【发布时间】:2021-12-19 08:19:54
【问题描述】:

我正在尝试编写一种 YouTube 下载器,它采用 YouTube 视频网址,使用请求和 BeautifulSoup 从在线视频下载器中抓取该视频的下载链接。

使用的网站 - https://www.y2mate.com/

方法:上述网站的漂亮功能,允许以下内容: 使用https://www.youtubepp.com/,后跟视频链接,例如https://www.youtube.com/watch?v=dQw4w9WgXcQ
这样做会将您带到该网站,并且 YouTube 视频已在搜索栏中输入。
因此,这允许在 requests 模块中使用这种特殊链接来提取所需的链接。

问题:

  1. 检查下载链接显示 href 像这样(对于 480p 下载): <a href="javascript:void(0)" rel="nofollow" type="button" class="btn btn-success" data-toggle="modal" data-target="#progress" data-ftype="mp4" data-fquality="480"> <i class="glyphicon glyphicon-download-alt"></i>  Download </a>

    如何从href="javascript:void(0) 中提取链接?
    我调查了this 所以问题,但它对我没有帮助,因为我找不到 onClick 属性

  2. 除了这个问题,我运行了以下代码来提取页面的html:

    from bs4 import BeautifulSoup
    import requests
    
    DOMAIN = "https://www.youtubepp.com/"
    URL = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    
    download_url = DOMAIN + URL
    
    params = {
      "hl": "en"    # I needed this because by default I was not getting English
    }
    
    res = requests.get(download_url, params=params)
    soup = BeautifulSoup(res.text, "html.parser")
    
    print(soup.prettify())
    

在检查输出时,我发现包含我需要的链接的部分甚至没有显示。 如果用beautifulsoup解析后甚至没有下载链接,我该如何成功提取下载链接。

替代尝试:

由于第一个问题,我尝试使用不同的网站来提取下载链接。
在这个网站中,我们可以使用https://www.ssyoutube.com/ 后跟视频链接的watch?v=dQw4w9WgXcQ 部分(http://youtube.com/watch?v=dQw4w9WgXcQ

这确实解决了第一个问题,但是使用这个网站也发现了第二个问题


EDIT 3(@Lima 回复后)

我尝试了不使用正则表达式的方法,但它给出了同样的错误,原因很明显你的调试消息

Jim Yosef - Link [NCS Release]
DEBUG:
DEBUG:  (<- need to bee the value of var k__id)
1: {'quality': '1080p HFR', 'type': 'mp4'}
2: {'quality': '720p HFR', 'type': 'mp4'}
3: {'quality': '480', 'type': 'mp4'}
4: {'quality': '360', 'type': 'mp4'}
5: {'quality': '240p', 'type': 'mp4'}
6: {'quality': '144p', 'type': 'mp4'}
7: {'quality': '144p', 'type': '3gp'}
8: {'quality': '128', 'type': 'mp3'}
9: {'quality': '128', 'type': 'mp3'}
Select stream [1-9]: 3
Traceback (most recent call last):
  File "c:\Users\rayya\Other\Web_Scraping\Youtube Download\sol2.py", line 71, in <module>
    toDownload = download.attrs["href"]
AttributeError: 'NoneType' object has no attribute 'attrs'

所以由于某种原因.getText() 方法返回None(我相信它返回 None 因为该输出)。这告诉我上次也是同样的问题,.getText() 会返回None,然后regex 找不到任何匹配项。

但是,因为您说我们正在寻找 var k_id 值。我尝试使用我的“修复”来获取&lt;script&gt; 标记,然后在其上使用正则表达式来获取var k_id 的值。

myScript = soup.findAll("script", {"type": "text/javascript"})[0]   # instead of using the .find().getText() method
print("DEBUG:", myScript)    # this worked, I skipped it in the output cuz of clutter

getId = re.compile(r'(?<=var k__id = ")\w*(?=";)')
tmpID = getId.findall(myScript)[0]
print("DEBUG:", tmpID, "(<- need to bee the value of var k__id)")

不幸报错如下:

Traceback (most recent call last):
  File "c:\Users\rayya\Other\Web_Scraping\Youtube Download\main.py", line 62, in <module>
    tmpID = getId.findall(myScript)[0]
  File "C:\Users\rayya\AppData\Local\Programs\Python\Python39\lib\re.py", line 241, in findall
    return _compile(pattern, flags).findall(string)
TypeError: expected string or bytes-like object

但是但是...
我打印了type(myScript) 并得到了&lt;class 'bs4.element.Tag'&gt;
我现在要做的就是myScript = str(myScript),然后一切都像魅力一样。这对我来说就像音乐,但对我来说。 (不要问:)哈哈)


编辑(尝试@Lima 的解决方案后)

我收到以下错误(我使用了您评论的视频 ID:

Youtube video id: 9iHM6X6uUH8
Jim Yosef - Link [NCS Release]
Traceback (most recent call last):
  File "c:\Users\rayya\Other\Web_Scraping\Youtube Download\main.py", line 58, in <module>
    tmpID = re.findall(getId, soup.find("script", {"type": "text/javascript"}).getText())[0]
IndexError: list index out of range

EDIT 2(检查错误)

我注意到在tmpID = re.findall(getId, soup.find("script",("type": "text/javascript"}).getText())[0] 行中,我们正在寻找与"script""type text/javascript" 相关的内容

所以在soup的声明之后,我打印了soup.prettify()Here 是它的输出,您注意到第 273 行是我们正在寻找的东西,但由于某种原因找不到它

我尝试通过几乎复制下面links 变量声明的语法来将行更改为tmpID = soup.findAll("script", {"type": "text/javascript"})[0]它奏效了

但是...
现在它给出了一个全新的错误

Traceback (most recent call last):
  File "c:\Users\rayya\Other\Web_Scraping\Youtube Download\main.py", line 91, in <module>
    toDownload = download.attrs["href"]
AttributeError: 'NoneType' object has no attribute 'attrs'

同样,我打印了soup.prettify(),但这次是在soup 的第二次声明之后。 This 是输出。而且我不知道如何进一步进行

【问题讨论】:

  • 我可以推荐yt-dlppytube下载YouTube视频
  • @Lima 我之前已经用 pytube 做了一个。我制作这个有两个原因,a)带有 pytube 的那个现在给我一个导入错误,即使我已经安装了它,b)我想在网络抓取方面做得更好。不过,我会检查一下 yt-dlp。感谢您的建议

标签: javascript python html beautifulsoup python-requests


【解决方案1】:

编辑:我避免使用正则表达式:

#!/usr/bin/python3
from bs4 import BeautifulSoup
from urllib import parse
import requests, json#, re

Id = parse.quote(input("Youtube video id: ")) # Like: 9iHM6X6uUH8

res = requests.post("https://www.y2mate.com/mates/en115/analyze/ajax",
                  headers={
                      "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                      "X-Requested-With": "XMLHttpRequest",
                      "Alt-Used": "www.y2mate.com",
                      "Sec-Fetch-Dest": "empty",
                      "Sec-Fetch-Mode": "cors",
                      "Sec-Fetch-Site": "same-origin"
                      },
                  data="url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D{}&q_auto=0&ajax=1".format(Id)
                  )
data = json.loads(res.content)
if not data['status'] == 'success':
    raise RuntimeError(f"data['status'] == {data['status']}")
soup = BeautifulSoup(data['result'], "html.parser")
if not soup.findChild().attrs['class'] == ['tabs', 'row']:
    raise FileNotFoundError("Video does not exist")
name = soup.find('div', {'class': ['caption', 'text-left']}).findChild('b').getText()
print(name)
myScript = soup.find('script', {'type':'text/javascript'}).getText()
print('DEBUG:', myScript)
#getId = re.compile(r'(?<=var k__id = ")\w*(?=";)')
tmpID = myScript[70+len(name):70+24+len(name)] #re.findall(getId, myScript)[0]
print('DEBUG:', tmpID, '(<- need to bee the value of var k__id)')
links = soup.findAll('a', {'class': ["btn", "btn-success"]})
streams = []
for i, link in enumerate(links):
    stream = {
        'quality': link.attrs['data-fquality'],
        'type': link.attrs['data-ftype']
        }
    streams.append(stream)
    print(f'{i+1}: {stream}')

myStream = streams[int(input(f"Select stream [1-{len(streams)}]: "))-1]

res = requests.post("https://www.y2mate.com/mates/convert",
                    headers={
                        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                        "X-Requested-With": "XMLHttpRequest",
                        "Alt-Used": "www.y2mate.com",
                        "Sec-Fetch-Dest": "empty",
                        "Sec-Fetch-Mode": "cors",
                        "Sec-Fetch-Site": "same-origin"
                        },
                    data="type=youtube&_id={verify}&v_id={vid}&ajax=1&token=&ftype={type}&fquality={quality}" \
                        .format(**myStream, verify=tmpID, vid=Id)
                    )

data = json.loads(res.content)
if not data['status'] == 'success':
    raise RuntimeError(f"data['status'] == {data['status']}")
soup = BeautifulSoup(data['result'], "html.parser")
download = soup.find('a', {'class': ['btn', 'btn-success', 'btn-file']})
toDownload = download.attrs['href']

print('Here is the download link:')
print(toDownload)

我是用 chrome devtools 发现的:

  • 我打开了网络标签
  • 粘贴了一个 yt 网址
  • 点击了下载按钮
  • 我看到了 2 个 POST 请求(发往哪个 url,带有标题、日期和响应)

【讨论】:

  • 好的,首先,非常感谢您的努力,我真的很感激。现在,我收到一个错误,请检查我的编辑
  • 所以我做了一些修改,虽然我对此不太了解,但我还是能够取得一些进展。请检查我的编辑
  • 第 273 行是我们正在寻找的东西:是的,但我想从脚本中提取变量 var k__id = "6135a4f9f99cc55e408b45c7";。我需要发回这个值才能下载:.format(**myStream, verify=tmpID, vid=Id)。我使用正则表达式(?&lt;=var k__id = ")\w*(?=";) 提取var k__id = ""; 之间的所有内容。这个 tmpID = soup.findAll("script", {"type": "text/javascript"})[0] 修复不好,因为我们只需要发回 k__id的价值。修复后的花药错误是,服务器响应错误消息,并且汤没有找到任何
  • 哦,我明白了,这是有道理的。我很好奇,不应该 data["status"] == "success" 返回 False 因为服务器响应错误消息?
  • 服务器向站点返回成功以呈现错误html消息。如果服务器端出现错误,我认为服务器会返回其他内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 2016-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多