2016-01-18 171 views
1

我想刮一個網站。我想刮的網站沒有API。HTTPoison與餅乾

我想要做的是(在Python):

import requests 

with requests.Session() as conn: 
    url = "http://demo.ilias.de/login.php" 
    auth = { 
     "username": "benjamin", 
     "password": "iliasdemo" 
    } 
    conn.post(url, data=auth) 
    response = conn.get(url) 
    do_work(response) 

當試圖做HTTPoison同樣的事情,網站響應「在瀏覽器中請啓用會話cookie!」。藥劑代碼:

HTTPoison.post "http://demo.ilias.de/login.php", 
    "{\"username\":\"benjamin\", \"password\":\"iliasdemo\"}" 

我想問題是用cookies。

UPD#1。這似乎並不是所有的餅乾,因爲:hackney.cookies(headers)保存(headers%HTTPoison.Response{headers: headers}是)不輸出一些這些Cookie(例如authchallenge)我看到我的瀏覽器,在上面的Python代碼的響應兩者。 hackney實際上不會發布任何內容嗎?

+0

我不能完全確定,因爲我從來沒有直接使用HTTPoison,但確實線路108在此[測試文件(https://github.com/edgurgel/httpoison/blob/3a456d39461f778c8eeac855445b77f772100cc7/test/httpoison_test.exs)幫你呢? –

+0

@ ham-sandwich在測試文件中,他們發送一個cookie。在我的請求時,我沒有任何cookie發送 - 我應該以某種方式存儲它。有一個[哈克尼圖書館](https://github.com/benoitc/hackney/blob/master/doc/hackney_cookie.md),我認爲這樣做。我只是不知道如何使用它。 – koolhazcker

回答

0

我有一個類似的問題:

我做一個GET請求到服務器API和它在同一位置的301重定向和「設置Cookie」用的sessionId頭響應。如果您在不重新發送cookie的情況下執行重定向,則它們會使用相同的重定向和新的SessionId cookie進行響應。如果你從未寄回他們的cookie,這個動機就像這樣繼續。另一方面,如果您將他們的cookie發回給他們,他們會回覆一個200狀態碼和您要求的數據。

問題是哈克尼,因此HTTPoison不能按照此方案。 它實際上有一個:follow_redirect選項,它在設置時遵循重定向,但在抓取cookie並在重定向之間將它們發送回去時不足。

所有瀏覽器我試過(火狐,Chrome,IE),其中能夠通過此方案。 Python和wget也完成了這項工作。

無論如何,長話短說,我寫我的一種替代方法可能提供一些想法和你有類似的問題:

defmodule GVHTTP do 
    defmacro __using__(_) do 
    quote do 
     use HTTPoison.Base 

     def cookies_from_resp_headers(recv_headers) when is_list(recv_headers) do 
     List.foldl(recv_headers, [], fn 
      {"Set-Cookie", c}, acc -> [c|acc] 
      _, acc -> acc 
     end) 
     |> Enum.map(fn(raw_cookie) -> 
      :hackney_cookie.parse_cookie(raw_cookie) 
      |> (fn 
        [{cookie_name, cookie_value} | cookie_opts] -> 
        { cookie_name, cookie_value, 
         cookie_opts 
        } 
        _error -> 
        nil 
       end).() 
     end) 
     |> Enum.filter(fn 
      nil -> false 
      _ -> true 
     end) 
     end 

     def to_request_cookie(cookies) do 
     cookies 
     |> Enum.map(fn({ cookie_name, cookie_value, _cookie_opts}) -> 
      cookie_name <> "=" <> cookie_value 
      end) 
     |> Enum.join("; ") 
     |> (&("" == &1 && [] || [&1])).() # "" => [], "foo1=abc" => ["foo1=abc"] 
     end 

     def get(url, headers \\ [], options \\ []) do 
     case options[:follow_redirect] do 
      true -> 
      hackney_options = case options[:max_redirect] do 
       0 -> options # allow HTTPoison to handle the case of max_redirect overflow error 
       _ -> Keyword.drop(options, [:follow_redirect, :max_redirect]) 
      end 
      case request(:get, url, "", headers, hackney_options) do 
       {:ok, %HTTPoison.Response{status_code: code, headers: recv_headers}} when code in [301, 302, 307] -> 
       {_, location} = List.keyfind(recv_headers, "Location", 0) 
       req_cookie = 
        cookies_from_resp_headers(recv_headers) 
        |> to_request_cookie() 

       new_options = 
        options 
        |> Keyword.put(:max_redirect, (options[:max_redirect] || 5) - 1) 
        |> Keyword.put(:hackney, [cookie: 
         [options[:hackney][:cookie]|req_cookie] 
         |> List.delete(nil) 
         |> Enum.join("; ") 
         ]) # add any new cookies along with the previous ones to the request 
       get(location, headers, new_options) 
       resp -> 
       resp 
      end 
      _ -> 
      request(:get, url, "", headers, options) 
     end 
     end 

    end # quote end 
    end # __using__ end 
end