Web Scraping - 识别和执行请求;故障排除

时间:2021-02-02 13:59:07

标签: python web-scraping python-requests web-inspector

我在从以下网站抓取数据时遇到了一些问题:https://www.loft.com.br/apartamentos/sao-paulo-sp?q=pin

当我们加载页面时,它加载了圣保罗市真实状态的前约 30 个帖子。 如果我们向下滚动,它会加载更多帖子。

通常我会使用 selenium 来解决这个问题——但我想学习如何正确地做到这一点——我想那是通过摆弄请求。

通过在 chrome 上使用检查,并观察当我们向下滚动时会发生什么,我可以看到一个请求,我认为是检索新帖子的请求。

enter image description here

如果我将其内容复制为 curl,则会得到以下命令:

curl "https://landscape-api.loft.com.br/listing/search?city=S^%^C3^%^A3o^%^20Paulo^&facetFilters^\[^\]=address.city^%^3AS^%^C3^%^A3o^%^20Paulo^&limit=18^&limitedColumns=true^&loftUserId=417b37df-19ab-4014-a800-688c5acc039d^&offset=28^&orderBy^\[^\]=rankB^&orderByStatus=^%^27FOR_SALE^%^27^%^2C^%^20^%^27JUST_LISTED^%^27^%^2C^%^20^%^27DEMOLITION^%^27^%^2C^%^20^%^27COMING_SOON^%^27^%^20^%^2C^%^20^%^27SOLD^%^27^&originType=LISTINGS_LOAD_MORE^&q=pin^&status^\[^\]=FOR_SALE^&status^\[^\]=JUST_LISTED^&status^\[^\]=DEMOLITION^&status^\[^\]=COMING_SOON^&status^\[^\]=SOLD" ^
  -X "OPTIONS" ^
  -H "Connection: keep-alive" ^
  -H "Accept: */*" ^
  -H "Access-Control-Request-Method: GET" ^
  -H "Access-Control-Request-Headers: loft_user_id,loftuserid,utm_campaign,utm_content,utm_created_at,utm_id,utm_medium,utm_source,utm_term,utm_user_agent,x-user-agent,x-utm-source,x-utm-user-id" ^
  -H "Origin: https://www.loft.com.br" ^
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36" ^
  -H "Sec-Fetch-Mode: cors" ^
  -H "Sec-Fetch-Site: same-site" ^
  -H "Sec-Fetch-Dest: empty" ^
  -H "Referer: https://www.loft.com.br/" ^
  -H "Accept-Language: en-US,en;q=0.9" ^
  --compressed

我不确定将其转换为要在 python 模块 requests 中使用的命令的正确方法 - 所以我使用了这个网站 - https://curl.trillworks.com/ - 来做到这一点。< /p>

结果是:

import requests

headers = {
    'Connection': 'keep-alive',
    'Accept': '*/*',
    'Access-Control-Request-Method': 'GET',
    'Access-Control-Request-Headers': 'loft_user_id,loftuserid,utm_campaign,utm_content,utm_created_at,utm_id,utm_medium,utm_source,utm_term,utm_user_agent,x-user-agent,x-utm-source,x-utm-user-id',
    'Origin': 'https://www.loft.com.br',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    'Sec-Fetch-Dest': 'empty',
    'Referer': 'https://www.loft.com.br/',
    'Accept-Language': 'en-US,en;q=0.9',
}

params = (
    ('city', 'S\xE3o Paulo'),
    ('facetFilters/[/]', 'address.city:S\xE3o Paulo'),
    ('limit', '18'),
    ('limitedColumns', 'true'),
    ('loftUserId', '417b37df-19ab-4014-a800-688c5acc039d'),
    ('offset', '28'),
    ('orderBy/[/]', 'rankB'),
    ('orderByStatus', '\'FOR_SALE\', \'JUST_LISTED\', \'DEMOLITION\', \'COMING_SOON\' , \'SOLD\''),
    ('originType', 'LISTINGS_LOAD_MORE'),
    ('q', 'pin'),
    ('status/[/]', ['FOR_SALE', 'JUST_LISTED', 'DEMOLITION', 'COMING_SOON', 'SOLD']),
)

response = requests.options('https://landscape-api.loft.com.br/listing/search', headers=headers, params=params)

但是,当我尝试运行它时,我得到了 204

所以我的问题是:

  1. 识别来自本网站的请求的正确/最佳方法是什么?有没有比我所做的更好的替代方法?
  2. 一旦确定,copy as curl 是复制命令的最佳方式吗?
  3. 如何最好地在 Python 中复制命令?
  4. 为什么我会得到 204?

2 个答案:

答案 0 :(得分:1)

<块引用>

1- 你做对了!很长一段时间以来,我一直以同样的方式这样做,并且根据我在网络抓取方面的经验,使用 your browser network tab 是迄今为止获取有关网站上发出的请求的信息的最佳方式,比任何“扩展”都要好和/或我知道的“插件”!!! kali linuxon windows 上也有“burpsuit”,但浏览器上的网络选项卡始终是我的第一选择!

<块引用>

2- 我一直在使用你提到的同一个网站!!!它使我的生活更轻松,并且可以无缝地正常工作。当然,您可以手动完成,但是您提到的网站对我来说更轻松,更快捷,而且我已经使用它很长时间了!

<块引用>

3- 您可以手动完成,这很简单,但就像我说的,您提到的网站使它变得更容易和更快。

<块引用>

4- 可能是因为您使用的是 requests.options,我会尝试使用 requests.get 来代替!!!

答案 1 :(得分:1)

您查找请求的方式是正确的。但是你需要找到并分析正确​​的请求。
关于为什么你得到 204 响应代码而没有结果;您发送 OPTION 请求而不是 GET。在 Chrome DevTools 中,您可以看到两个类似的请求(查看附件图片)。一个是 OPTION,第二个是 GET,类型为 xhr
对于网站,您需要第二个,但您在代码中使用了 OPTION requests.options(..) enter image description here 要查看请求的响应,请选择它并检查响应或预览选项卡。 enter image description here

Python 中最好的 HTTP 库之一是

这里是获取所有搜索结果的完整代码:

import requests

headers = {
    'x-user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_0) AppleWebKit/537.36 (KHTML, like Gecko) '
                    'Chrome/88.0.4324.146 Safari/537.36',
    'utm_created_at': '',
    'Accept': 'application/json, text/plain, */*',
}

with requests.Session() as s:
    s.headers = headers

    listings = list()
    limit = 18
    offset = 0
    while True:
        params = {
            "city": "São Paulo",
            "facetFilters/[/]": "address.city:São Paulo",
            "limit": limit,
            "limitedColumns": "true",
            # "loftUserId": "a2531ad4-cc3f-49b0-8828-e78fb489def8",
            "offset": offset,
            "orderBy/[/]": "rankA",
            "orderByStatus": "\'FOR_SALE\', \'JUST_LISTED\', \'DEMOLITION\', \'COMING_SOON\' , \'SOLD\'",
            "originType": "LISTINGS_LOAD_MORE",
            "q": "pin",
            "status/[/]": ["FOR_SALE", "JUST_LISTED", "DEMOLITION", "COMING_SOON", "SOLD"]
        }
        r = s.get('https://landscape-api.loft.com.br/listing/search', params=params)
        r.raise_for_status()

        data = r.json()
        listings.extend(data["listings"])

        offset += limit
        total = data["pagination"]["total"]
        if len(data["listings"]) == 0 or len(listings) == total:
            break

print(len(listings))