【问题标题】:302 Redirect in xhr requestxhr 请求中的 302 重定向
【发布时间】:2017-12-25 05:29:43
【问题描述】:

我需要向这个网址发送一个帖子请求:

http://lastsecond.ir/hotels/ajax

您可以在此处查看此请求发送的其他参数:

formdata:

filter_score:
sort:reviewed_at
duration:0
page:1
base_location_id:1

request header: 

:authority:lastsecond.ir
:method:POST
:path:/hotels/ajax
:scheme:https
accept:*/*
accept-encoding:gzip, deflate, br
accept-language:en-US,en;q=0.9,fa;q=0.8,ja;q=0.7
content-length:67
content-type:application/x-www-form-urlencoded; charset=UTF-8
cookie:_jsuid=2453861291; read_announcements=,11,11; _ga=GA1.2.2083988810.1511607903; _gid=GA1.2.1166842676.1513922852; XSRF-TOKEN=eyJpdiI6IlZ2TklPcnFWU3AzMlVVa0k3a2xcL2dnPT0iLCJ2YWx1ZSI6ImVjVmt2c05STWRTUnJod1IwKzRPNk4wS2lST0k1UTk2czZwZXJxT2FQNmppNkdUSFdPK29kU29RVHlXbm1McTlFSlM5VlIwbGNhVUozbXFBbld5c2tRPT0iLCJtYWMiOiI4YmNiMGQwMzdlZDgyZTE2YWNlMWY1YjdmMzViNDQwMmRjZGE4YjFmMmM1ZmUyNTQ0NmE1MGRjODFiNjMwMzMwIn0%3D; lastsecond-session=eyJpdiI6ImNZQjdSaHhQM1lZaFJIZzhJMWJXN0E9PSIsInZhbHVlIjoiK1NWdHJiUTdZQzBYeEsyUjE3QXFhUGJrQXBGcExDMVBXTjhpSVJLRlFnUjVqXC9USHBxNGVEZ3dwKzVGcG5yeU93VTZncG9wRGpvK0VpVnQ2b1ByVnh3PT0iLCJtYWMiOiI4NTFkYmQxZTFlMTMxOWFmZmU1ZjA1ZGZhNTMwNDFmZmU0N2FjMGVjZTg1OGU2NGE0YTNmMTc2MDA5NWM1Njg3In0%3D
origin:https://lastsecond.ir
referer:https://lastsecond.ir/hotels?score=&page=1&sort=reviewed_at&duration=0
user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
x-csrf-token:oMpQTG0wN0YveJIk2WhkesvzjZE2FqHkDqPiW8Dy
x-requested-with:XMLHttpRequest

这段代码的结果假设是一个 json 文件,它将请求重定向到其父 url。我正在使用scrapy和python来发送这个请求,这里是scrapy代码:

class HotelsSpider(scrapy.Spider):
    name = 'hotels'
    allowed_domains = ['lastsecond.ir']
    start_urls = ['http://lastsecond.ir/hotels']

    def parse(self, response):
        data = {
            'filter_score': '',
            'sort': 'reviewed_at',
            'duration': '0',
            'page': '1',
            'base_location_id': '1'
        }
        headers = {
            'user-agent': 'Mozilla/5.0',
            'x-csrf-token': 'oMpQTG0wN0YveJIk2WhkesvzjZE2FqHkDqPiW8Dy',
            'x-requested-with': 'XMLHttpRequest'
        }
        url = 'https://lastsecond.ir/hotels/ajax'
        return FormRequest(
            url=url,
            callback=self.parse_details,
            formdata=data,
            method="POST",
            headers=headers,
            dont_filter=True
        )

    def parse_details(self, response):
        data = response.body_as_unicode()
        print(data)
        #f = open('output.json', 'w')
        #f.write(data)
        #f.close()

我已经更改了我的代码,因此它每次发送请求时都会获得新的 csrf-token:

class HotelsSpider(scrapy.Spider):
    name = 'hotels'
    allowed_domains = ['lastsecond.ir']
    start_urls = ['http://lastsecond.ir/hotels']

    def parse(self, response):
        html = response.body_as_unicode()
        start = html.find("var csrftoken = '")
        start = start + len(b"var csrftoken = '")
        end = html.find("';", start)

        self.csrftoken = html[start:end]

        print('csrftoken:', self.csrftoken)
        yield self.ajax_request('1')

    def ajax_request(self, page):
        data = {
            'filter_score': '',
            'sort': 'reviewed_at',
            'duration': '0',
            'page': page,
            'base_location_id': '1'
        }
        headers = {
            'user-agent': 'Mozilla/5.0',
            'x-csrf-token': self.csrftoken,
            'x-requested-with': 'XMLHttpRequest'
        }
        url = 'https://lastsecond.ir/hotels/ajax'
        return FormRequest(
            url=url,
            callback=self.parse_details,
            formdata=data,
            method="POST",
            headers=headers,
            dont_filter=True
        )

    def parse_details(self, response):
        print(response.body_as_unicode())

任何帮助将不胜感激。

【问题讨论】:

  • 每个请求都需要新的 uniqe 'x-csrf-token' - 你不能总是使用相同的。请参阅我对上一个问题的回答 - 我使用 GETHTML 获取新的 'x-csrf-token'
  • 永远不要改变问题。现在我的回答不适合你的问题。如果您更改了代码但仍有问题,请附加到原始问题或创建新问题。
  • 我按你说的解决了这个问题,很抱歉改变了原来的问题。你现在可以指导我吗?
  • 我将您的代码作为独立脚本进行了尝试,得到了正确的结果。也许有不同的问题。也许服务器出于某种原因阻止了您 - 它不喜欢您的 IP,或者您发出了很多请求并且它知道您运行脚本。在parse_details 你可以试试from scrapy.commands.view import open_in_browser ; open_in_browser(response) 它应该在浏览器中显示HTML(你在302之后得到)。

标签: python http scrapy


【解决方案1】:

你的错误在每个请求中都是相同的'x-csrf-token'

'x-csrf-token' 是阻止机器人/脚本的方法。

维基百科:Cross Site Request Forgery

每次您在浏览器门户中打开页面时,都会生成新的、唯一的'x-csrf-token',它只能在短时间内正确。你不能一直使用同一个'x-csrf-token'

在回答上一个问题时,我提出GET 请求获取页面并找到新鲜的X-CSRF-TOKEN

在代码中查看self.csrftoken

def parse(self, response):
    print('url:', response.url)

    html = response.body_as_unicode()

    start = html.find("var csrftoken = '")
    start = start + len(b"var csrftoken = '")
    end = html.find("';" , start)

    self.csrftoken = html[start:end]

    print('csrftoken:', self.csrftoken)

    yield self.create_ajax_request('1')

后来我使用这个令牌来读取 AJAX 请求。

def create_ajax_request(self, page):
    ''' 
    subfunction can't use `yield, it has to `return` Request to `parser`
    and `parser` can use `yield`
    '''

    print('yield page:', page)

    url = 'https://lastsecond.ir/hotels/ajax'

    headers = {
        'X-CSRF-TOKEN': self.csrftoken,
        'X-Requested-With': 'XMLHttpRequest',
    }

    params = {
        'filter_score': '',
        'sort': 'reviewed_at',
        'duration': '0',
        'page': page,
        'base_location_id': '1',
    }

    return scrapy.FormRequest(url, 
        callback=self.parse_details, 
        formdata=params, 
        headers=headers, 
        dont_filter=True, 
    )

【讨论】:

  • 感谢您的有用回答,我编辑了我的代码,使其每次都能获得新的 csrf 令牌,但仍会收到 302 重定向和 html 响应。
【解决方案2】:

您是否提出非法请求?学习它的最简单方法是将浏览器中的请求复制为 curl(F12 -> Network -> Right Click on specified request -> Copy -> Copy as Curl),然后使用this tool(不带 Scrapy)将其转换为 python 语言

【讨论】:

    猜你喜欢
    • 2011-04-18
    • 2017-03-09
    • 2015-07-29
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    相关资源
    最近更新 更多