【问题标题】:Issue in Web Scraping网页抓取问题
【发布时间】:2020-07-03 03:11:37
【问题描述】:

我正在尝试在 PyCharm 中编写一个程序(我以前没有使用过这个 IDE,但我认为这不是问题)我遇到了从某个 class、"react-contextmenu-wrapper"

收集数据的麻烦

我想编写一个脚本来解析 Spotify 上的网页并使用数据创建一个 CSV 文件,我一直在关注 YouTube 上的教程,但我一定是在某个地方出错了。

这是我的代码:

from urllib.request import urlopen as Req
from bs4 import BeautifulSoup as soup

my_url = "https://open.spotify.com/genre/NMF-PopularNewReleases"

#grabs the contense of the page
Client = Req(my_url)

#reads the contense of the page
html = Client.read()

#outputs the page
Client.close()

page = soup(html, "html.parser")

#grabs each playlist
playlists = page.findAll("div",{"class":"react-contextmenu-wrapper"})

print(len(playlists))

但是终端输出一个空列表,我知道该类存在。当我检查页面的元素时,我可以查看它。

【问题讨论】:

    标签: python html web-scraping


    【解决方案1】:

    元素的类被命名为react-contextmenu-wrapper 的事实是一个很大的提示。 React 是一个用于创建用户界面的 JavaScript 库。

    可以通过多种方式在网页中填充元素。如果幸运的话,服务器会向您发送一个.html,其中包含所有基本已烘焙的内容 - 这对于使用 BeautifulSoup 进行抓取和解析是微不足道的。

    但是,许多现代网站会动态填充网页的元素,例如使用 JavaScript。当您在浏览器中查看这样的页面时,这没问题 - 但如果您尝试抓取这样的页面,您最终会得到“基本”模板.html,其中 DOM 尚未填充完全。这就是 BeautifulSoup 看不到这个元素的原因。

    重点是:仅仅因为您可以在浏览器中看到一个元素,并不意味着 BeautifulSoup 就能看到它。

    在我看来,每当你想抓取网页时,你的首选武器不应该是 BeautifulSoup - 你应该使用 BeautifulSoup 作为最后的手段。您应该始终做的第一件事是检查您正在抓取的页面是否向 API 发出任何请求,其响应用于填充自身。如果是这样,您可以简单地模仿对同一 API 的请求,并获取您可能想要抓取的所有内容。好像这还不够好,这些 API 通常提供 JSON,解析起来很简单。

    你是这样做的:

    1. 在浏览器中打开网页。
    2. 如果您使用的是 Google Chrome,请按 F12 键访问 开发者工具(其他现代浏览器应该有类似的 功能。)
    3. 打开“网络”选项卡。我们将使用 Chrome 的网络记录器来记录 网页发出的所有请求。
    4. 单击漏斗形图标(激活时变为红色)以 启用过滤。
    5. 单击 XHR(这意味着仅查看 XMLHttpRequests。这些是 我们感兴趣的请求,因为我们想看到 对 API 的潜在传出请求 - 我们对捕获对图像等资源发出的请求不感兴趣)
    6. 按Ctrl + E或点击左上角的圆形记录按钮 启用日志记录(此选项在激活时也会变为红色。)
    7. 按Ctrl + R 刷新页面并开始记录流量。
    8. 您应该会看到请求列表随着页面加载而增加 清爽。它看起来像这样(对不起,大 图片):
    9. 就我而言,Spotify 在 我记录流量的时间。我点击了其中的一些,然后 检查他们的“标题”选项卡,直到我找到一个有“请求”的选项卡 URL”看起来像是在与 API 对话(“api”是 本例中的 URL。)

    是时候使用requests 编写一个简单的脚本了。你会想要复制 “请求 URL”,并确保复制一些“请求标头” 看起来它们对请求也很重要:

    import requests
    
    url = "https://api.spotify.com/v1/views/NMF-PopularNewReleases?timestamp=2020-03-22T14%3A26%3A36.760Z&platform=web&content_limit=10&limit=20&types=album%2Cplaylist%2Cartist%2Cshow%2Cstation&image_style=gradient_overlay&country=us&market=us&locale=en"
    
    headers = {
        "Authorization": "Bearer BQDJeAA33JWAC_pQVUxoPpama63RFFIsovMjNOjq_odaPx9EfyMz1Bo494Xv4a20H9gM7Hu0OYZrO3QWs2E"
    }
    
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    
    data = response.json()
    
    for item in data["content"]["items"]:
        print(item["name"])
    

    当我运行这个脚本时,我得到以下输出:

    New Music Friday
    After Hours
    Colores
    kelsea
    Actions
    Kid Krow
    Walk Em Down (feat. Roddy Ricch)
    Studio It’s Hits
    Intentions (Acoustic)
    Creep
    Is Everybody Going Crazy?
    2 Seater (feat. G-Eazy & Offset)
    Roses/Lotus/Violet/Iris
    Spotify Singles
    Between Us (feat. Snoh Aalegra)
    E.P.
    Black Men Don’t Cheat (feat. Ari Lennox, 6LACK & Tink)
    Think About You
    Pray 4 Love
    Acrobats
    >>> 
    

    随意检查 API 返回的 JSON 对象 - 您可以在 Python 中执行此操作,也可以通过从 Chrome 开发者工具中的“标题”选项卡切换到“预览”选项卡来查看 JSON 的内容。在我的示例中,我只是在首页提取歌曲的标题,但 JSON 对象包含更多有趣的内容。您还可以使用 URL 的查询字符串中的参数来抓取 20 多首歌曲等。

    【讨论】:

    • 非常感谢,您的表述非常清晰易懂
    • 另外,有没有办法使用参数来获取专辑的链接。抱歉,如果这是一个愚蠢的问题,这是我的第一个废品项目。
    • @t0mas 是的。在我发布的代码 sn-p 中,将 print(item["name"]) 更改为 print(item["href"]) 以打印每个专辑的 URL 而不是名称。
    猜你喜欢
    • 2021-07-25
    • 1970-01-01
    • 2016-02-05
    • 2015-06-26
    • 1970-01-01
    • 2023-03-04
    相关资源
    最近更新 更多