【问题标题】:Requests - determine parameterised url prior to issuing request, for inclusion in Referer header请求 - 在发出请求之前确定参数化 url,以包含在 Referer 标头中
【发布时间】:2014-12-21 05:06:15
【问题描述】:

我正在编写一个使用请求自动访问特定网站的 Python 2.7 脚本。出于“安全原因”,该网站要求提供与请求 URL 匹配的Referer 标头。 URL 由 params dict 中的多个项目构成,并传递给 requests.post()。

有没有办法在发出请求之前确定 Requests 将使用的 URL 是什么,以便可以将 Referer 标头设置为这个正确的值?假设我有很多参数:

params = { 'param1' : value1, 'param2' : value2, # ... etc
  }

base_url = "http://example.com"
headers = { 'Referer' : url }   # but what is 'url' to be?
requests.post(base_url, params=params, headers=headers)  # fails as Referer does not match final url

我想一种解决方法是在事后发出请求并查看 URL 是什么。然而,这有两个问题 - 1. 它增加了脚本执行时间的大量开销,因为会有很多这样的请求,以及 2. 它实际上不是一个有用的解决方法,因为服务器实际上将请求重定向到另一个URL,因此之后阅读它不会给出正确的 Referer 值。

我想指出,我有这个脚本与 urllib/urllib2 一起工作,我正在尝试用 Requests 来编写它,看看它是否可能并且可能更简单。这不是脚本必须遵循的复杂过程,但可能稍微超出了请求的范围。没关系,我只是想确认一下。

【问题讨论】:

    标签: python python-requests http-referer referer


    【解决方案1】:

    我想我找到了一个基于Prepared Requests 的解决方案。这个概念是Session.prepare_request() 将做所有事情来准备请求,除了发送它,这允许我的脚本然后读取准备好的请求的 url,它现在包括其顺序由 dict 顺序确定的参数。然后它可以适当地设置Referer头,然后发出原始请求。

    params = {'param1' : value1, 'param2' : value2, # ... etc
             }
    url = "http://example.com"
    
    # Referer must be correct
    # To determine correct Referer url, prepare a request without actually sending it
    req = requests.Request('POST', url, params=params)
    prepped = session.prepare_request(req)
    #r = session.send(prepped)   # don't actually send it
    
    # add the Referer header by examining the prepared url
    headers = { 'Referer': prepped.url }
    
    # now send normally
    r = session.post(url, params=params, data=data, headers=headers)
    

    【讨论】:

      【解决方案2】:

      您似乎在 Requests 中正确找到了 prepare_request 功能。

      但是,如果您仍然想使用您的初始方法,我相信您可以使用您的 base_url 作为您的Referer:

      base_url = "http://example.com"
      headers = { 'Referer' : base_url }
      requests.post(base_url, params=params, headers=headers)
      

      我怀疑这是因为您的 POST 将 PARAMS 直接附加到 base_url。例如,如果您在:

      http://www.example.com/trying-to-send-upload/
      

      向此 POST 添加一些参数,然后您将使用:

      referer = "http://www.example.com/trying-to-send-something/"
      headers = { 'Referer' : referer, 'Host' : 'example.com' }
      requests.post(referer, params=params, headers=headers)
      

      添加

      在您创建 URL 字符串后,我会使用一个简单的语句来直观地检查我的 URL:

      print(post_url)
      

      如果这很好,您应该打印出您要发布到的服务器的回复的详细信息,因为它还可能为您提供一些关于您的查询被拒绝的原因的提示:

      s = requests.post(referer, params=params, headers=headers)
      print(s.status_code)
      print(s.text)
      

      很想知道这是否也适合您。

      【讨论】:

      • 感谢您的建议。我试过这个,它返回 403。再深入一点,看起来这个站点的引用 URL 必须包含参数,否则它会被拒绝 - 这是这个特定站点的怪癖吗?
      • @meowsqueak,参数包含对服务器了解正在生成的 POST 至关重要的信息,参数 = 参数。这可能是搜索详细信息、页面详细信息等。403 Forbidden 错误很可能意味着您的 POST 未正确写入,或者您无权访问该页面。我通常会怀疑后者,但确保您创建了正确的帖子 URL 很重要。
      • 我要发布的这个服务要求引用 URL 与“to” URL 匹配,包括参数,我只能在它被编码后才能获得。这就是为什么我使用prepare_request - 对URL 进行编码,然后将其用于Referer。参数从 params 参数添加到基本 URL,因此它们最初在“to” URL 或引用 URL 中不是显式的。我认为最好让 Requests 处理 URL 编码,这就是我使用 params 参数的原因。
      • 在我看来,您听起来正确地理解了一切,并且正确地执行。实际代码将有助于识别问题。正如我上面所说,要解决此问题,您可以尝试一些事情。第一步尝试找出服务器响应 403 禁止错误的原因;是因为您的 POST 未正确编译(这是您的参数)?还是您没有正确验证?查看第一个的快速方法是在编译后 print(url) 。 Requests 也有关于打印您使用 Requests POST 命令发送的数据的文档。
      • 首先,感谢您对我的耐心等待。据我所知,服务器拒绝 POST,因为referer 标头不包含也包含 POST 参数的 URL。我无法从服务器获得更多信息,它不在我的控制之下。从本质上讲,在我看来,服务器要求请求 URL 和引用 URL 必须相同才能使 POST 成功。这可能是这个服务器的一个怪癖,它不是公开的,所以很遗憾我不能提供工作代码。对于服务器来说,这是一件不寻常的事情吗?
      猜你喜欢
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-07
      • 1970-01-01
      • 2016-11-14
      • 1970-01-01
      • 2017-02-24
      相关资源
      最近更新 更多