如何在Scrapy中发出需要请求有效负载的POST请求

时间:2019-10-07 14:48:37

标签: python web-scraping scrapy

我正在尝试从该website中解析数据。
在检查元素的“网络”部分中,我找到了该链接https://busfor.pl/api/v1/searches,该链接用于返回我感兴趣的JSON的POST请求。
但是对于发出此POST请求,需要使用一些字典来请求有效负载。
我假设它像普通的formdata一样,我们用来使FormRequest变得草率,但它返回403错误。

我已经尝试了以下方法。

url = "https://busfor.pl/api/v1/searches"
formdata = {"from_id" : d_id
                ,"to_id" : a_id
                ,"on" : '2019-10-10'
                ,"passengers" : 1
                ,"details" : []
}
yield scrapy.FormRequest(url, callback=self.parse, formdata=formdata)

这将返回 403错误
我还通过参考其中一个StackOverflow帖子对此进行了尝试。

url = "https://busfor.pl/api/v1/searches"
payload = [{"from_id" : d_id
                ,"to_id" : a_id
                ,"on" : '2019-10-10'
                ,"passengers" : 1
                ,"details" : []
}]
yield scrapy.Request(url, self.parse, method = "POST", body = json.dumps(payload))

但是即使这样也会返回相同的错误。
有人能帮我吗。弄清楚如何使用Scrapy解析所需的数据。

1 个答案:

答案 0 :(得分:0)

稍后会发送带有json数据的POST请求的方法,但是您将错误的json传递到站点,它需要一个字典,而不是字典列表。 所以代替:

payload = [{"from_id" : d_id
                ,"to_id" : a_id
                ,"on" : '2019-10-10'
                ,"passengers" : 1
                ,"details" : []
}]

您应该使用:

payload = {"from_id" : d_id
                ,"to_id" : a_id
                ,"on" : '2019-10-10'
                ,"passengers" : 1
                ,"details" : []
}

您没有注意到的另一件事是传递给POST请求的headers,有时站点使用ID和哈希值来控制对其API的访问,在这种情况下,我发现了两个似乎需要的值, X-CSRF-TokenX-NewRelic-ID。幸运的是,这两个值可在搜索页面上找到。

这是一个工作的蜘蛛,搜索结果可通过方法self.parse_search获得。

import json
import scrapy

class BusForSpider(scrapy.Spider):
    name = 'busfor'
    start_urls = ['https://busfor.pl/autobusy/Sopot/Gda%C5%84sk?from_id=62113&on=2019-10-09&passengers=1&search=true&to_id=3559']
    search_url = 'https://busfor.pl/api/v1/searches'

    def parse(self, response):
        payload = {"from_id" : '62113',
                   "to_id" : '3559',
                   "on" : '2019-10-10',
                   "passengers" : 1,
                   "details" : []}
        csrf_token = response.xpath('//meta[@name="csrf-token"]/@content').get()
        newrelic_id = response.xpath('//script/text()').re_first(r'xpid:"(.*?)"')
        headers = {
            'X-CSRF-Token': csrf_token,
            'X-NewRelic-ID': newrelic_id,
            'Content-Type': 'application/json; charset=UTF-8',
        }
        yield scrapy.Request(self.search_url, callback=self.parse_search, method="POST", body=json.dumps(payload), headers=headers)

    def parse_search(self, response):
        data = json.loads(response.text)