【问题标题】:Scrape dynamically loading page using beautifulsoup [closed]使用 beautifulsoup 抓取动态加载页面 [关闭]
【发布时间】:2019-12-18 11:49:51
【问题描述】:

我是 beautifulsoup 包的新手。我正在尝试从https://indianrecipes.com/new_and_popular 中抓取所有食物食谱和链接以及配料 问题是这个网站在向下滚动时只会加载更多的食物。我提到了这个问题Beautifulsoup - scrape webpage - dynamically loading page,但没有做太多。 我检查了检查元素中的网络选项卡,发现每次向下滚动时都会发送一个 XHR 请求

api?tm=1565542062069
api?tm=1565542065302
api?tm=1565542073116
api?tm=1565542075617

是否可以在 python 中模拟这样的请求以从该页面中提取所有食物食谱?

【问题讨论】:

  • 请尝试编写此代码并分享您遇到的问题。

标签: python html web-scraping beautifulsoup screen-scraping


【解决方案1】:

我制作了简单的脚本,您可以在其中指定每页的食谱数和要抓取的页数。它以 JSON 格式返回数据:

from itertools import count, islice
import requests
import json

url = 'https://indianrecipes.com/api'
data = {"id":1,"jsonrpc":"2.0","method":"recipe.get_trending","params":[50,50,None,False]}

per_page = 50
num_pages = 2

for i, c in enumerate( islice(count(0, per_page), 0, num_pages), 1):
    print('Page no.{} :'.format(i))
    print('-' * 80)
    data['params'][0] = c
    data['params'][1] = per_page
    json_data = requests.post(url, json=data).json()
    print(json.dumps(json_data, indent=4))
    print('-' * 80)

打印:

Page no.1 :
--------------------------------------------------------------------------------
{
    "id": 1,
    "jsonrpc": "2.0",
    "result": {
        "recipes": [
            {
                "has_video": false,
                "id": 8630002,
                "image_url": "//lh3.googleusercontent.com/zgZHuLeSg_lKRc66RycpaDoSVMULp3puzoignsoEH40DJBQtOpQi0Ub1L1ET52VFhd3ZUF8r8ZEiD_kEsZNQPloO3_T1KW9sbBE",
                "link": "//indianrecipes.com/recipe/Dahi-Vada_Ad3A",
                "name": "Dahi Vada",
                "rating": 5.0,
                "score": 0.0
            },
            {
                "has_video": false,
                "id": 9330018,
                "image_url": "//lh3.googleusercontent.com/HXd-CD3P0U_v4ItJplGsT5oKZ8mKAAA0AXRsgeOoeLeH4ggvyGRdx-6Y_J1H1EdRLv5De7b5oYqeHkBts4VwIpqBAHNA_OYP8g",
                "link": "//indianrecipes.com/recipe/French-Egg-Casserole_D9aa",
                "name": "French Egg Casserole",
                "rating": 0.0,
                "score": 0.0
            },

...and so on

【讨论】:

    【解决方案2】:

    api?tm=1565542075617 中的数字是纪元时间戳,以毫秒为单位。这对于请求可能不是必需的。

    重要的是查看请求发送的服务器将响应哪些数据。在 XHR 请求中向下滚动到 Request Payload 以查看有效负载。

    下面是一个 Python 代码,它在初始 offset 食谱数量之后加载 recipes_per_page 食谱数量。

    import requests
    
    offset = 50
    recipes_per_page = 50
    data = [{'jsonrpc': '2.0', 'method': 'recipe.get_trending', 'id': 1, 'params': [offset, recipes_per_page, None, False]}]
    response = requests.post('https://indianrecipes.com/api', json=data)
    
    recipes = response.json()[0]['result']['recipes']
    

    【讨论】:

    • 感谢您的回答,非常有帮助。不过我有一些疑问。 response.json() 是做什么的,如果我想将所有 response.json() 加载到一个漂亮的汤对象中,我应该怎么做。
    • response 是一个requests.Response 对象(参见here 中的文档)。 response.json() 假定响应为 JSON 格式,并尝试解析 response.content 并返回数据字典。由于来自服务器的响应是 JSON 格式,本质上您可以将其解析为 Python 字典。您不需要使用 Beautiful Soup,因为它应该用于 HTML/XML。我希望这会有所帮助。
    【解决方案3】:

    您必须使用 selenium 将 javascript 从网页加载到 html 然后使用 selenium 的滚动代码

    import requests
    from bs4 import BeautifulSoup
    from selenium import webdriver
    import pandas as pd
    import time
    from selenium.webdriver.common.keys import Keys
    
    driver = webdriver.Chrome('/home/sush/Downloads/Compressed/chromedriver_linux64/chromedriver')
    
    driver.get('https://indianrecipes.com/new_and_popular')
    
    
    heights = []
    counter = 0
    for i in range(1,300):
        bg = driver.find_element_by_css_selector('body')
        time.sleep(0.1)
        bg.send_keys(Keys.END)
        heights.append(driver.execute_script("return document.body.scrollHeight"))
        try :
            bottom = heights[i-16]
        except:
            pass
        if i%16 ==0:
            new_bottom = heights[i-1]
            if bottom == new_bottom:
                break
    

    然后使用beautifusoup 来抓取你需要的数据

    soup = BeautifulSoup(driver.page_source, 'lxml')

    【讨论】:

      猜你喜欢
      • 2018-01-18
      • 1970-01-01
      • 2015-05-08
      • 2017-07-24
      • 2015-03-27
      • 2022-06-13
      • 2019-03-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多