2017-11-15 11 views
3

URLからデータを取得する必要があります。GETを使用して複数のページからJSONデータを取得する

  1. 以下のコードは、「過去のファイルの終わりを読む」というエラーを示しています。 URLは正しいですが、ブラウザに貼り付けて結果を見ることができます。私はそれについて何かできることがあるかどうか確かではない、時間制限を超過しました。

  2. 問題は、データが複数のページにある可能性があることです。私はpage1からtotal_pagesを選択してループを実行する必要がありますか?より良い解決策はありますか?

ここにコードされています

string url="https://jsonmock.hackerrank.com/api/movies/search/?Title=spiderman&page=1"; 
string res=MakeRequest(url); 

MakeRequest:

static public string MakeRequest(string url) 
{ 

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 
    request.ContentType = "application/json; charset=utf-8"; 
    request.PreAuthenticate = true; 

HttpWebResponse response = request.GetResponse() as HttpWebResponse; 
    using (Stream responseStream = response.GetResponseStream()) 
    { 
     StreamReader reader = new StreamReader(responseStream, Encoding.UTF8); 
     return (reader.ReadToEnd()); 

    } 

} 

ここでは、データ(PAGE2)がHttpClientを使用して

{"page":"2","per_page":10,"total":13,"total_pages":2,"data":[{"Poster":"N/A","Title":"They Call Me Spiderman","Type":"movie","Year":2016,"imdbID":"tt5861236"},{"Poster":"N/A","Title":"The Death of Spiderman","Type":"movie","Year":2015,"imdbID":"tt5921428"},{"Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZDlmMGQwYmI[email protected]@._V1_SX300.jpg","Title":"Spiderman in Cannes","Type":"movie","Year":2016,"imdbID":"tt5978586"}]} 
+0

はいを​​省略してGetMoviesAsyncを()を改善多くのデータを取得するのを避けるために、複数のページが正常です。ただし、呼び出し回数が多すぎると感じる場合は、APIが大きなページ(ページあたりの項目数)を許可するかどうかを確認してください。 – Alexei

+0

完全な例外(スタックあり)も含めることができますか? – Alexei

+0

Alexei、 "しかし、あなたが過度の呼び出しを行っていると感じたら、APIが大きなページ(ページあたりの項目)を許可するかどうかを確認してください。 何を確認するかわかりません。唯一の方法は、ページのリクエストが失敗するまでループ内で別々に各ページからデータを取得することですか? – anjulis

答えて

1

完全な例のように見えるもので、 Newtonsoft.Json。

まず、我々のデータ転送はAPIから自分のJSONの対応に合わせて、オブジェクトのためのクラスを定義してみましょう:

public class PageResponse 
{ 
    public string Page { get; set;} 

    [JsonProperty("per_page")] 
    public int PerPage { get; set;} 

    public int Total { get; set; } 

    [JsonProperty("total_pages")] 
    public int TotalPages { get; set; } 

    public IEnumerable<Movie> Data { get; set; } 
} 

public class Movie 
{ 
    public string Poster { get; set; } 
    public string Title { get; set; } 
    public string Type { get; set; } 
    public int Year { get; set; } 

    [JsonProperty("imdbID")] 
    public string ImdbId { get; set; } 
} 

その後のは、DO-しばらくサイクルを使用しており、私たちまで、要求を実行するメソッドを呼び出すAPIを作成してみましょう(何らかの理由で)すべてのページを検索するか失敗のどちらか:

public static async Task<IEnumerable<Movie>> GetMoviesAsync() 
{ 
    var movies = new List<Movie>(); 
    var url = "http://jsonmock.hackerrank.com/api/movies/search/?Title=spiderman"; 
    int currentPage = 1; 
    int totalPages = 0; 
    var nextUrl = $"{url}&page={currentPage}"; 

    using (var httpClient = new HttpClient()) 
    { 
     do 
     { 
      HttpResponseMessage response = await httpClient.GetAsync(nextUrl); 

      if (response.IsSuccessStatusCode) 
      { 
       string json = await response.Content.ReadAsStringAsync(); 
       var pageResponse = JsonConvert.DeserializeObject<PageResponse>(json); 

       if (pageResponse != null && pageResponse.Data.Any()) 
       { 
        movies.AddRange(pageResponse.Data); 
        totalPages = pageResponse.TotalPages; 

        currentPage++; 
        nextUrl = $"{url}&page={currentPage}"; 
       } 
       else 
       { 
        break; // or throw exception 
       } 
      } 
      else 
      { 
       break; // or throw exception 
      } 
     } while (currentPage < totalPages); 
    } 

    return movies; 
} 

そして最後に私たちの主な方法からGetMoviesAsyncへの呼び出し:

static void Main(string[] args) 
{ 
    IEnumerable<Movie> movies = GetMoviesAsync().GetAwaiter().GetResult(); 
    Console.WriteLine($"Retrieved {movies.Count()} movies."); 
} 

が...この編集の時点で、これは13本の映画の総取得:サイドノートとしても

Retrieved 13 movies. 

を、ベストプラクティスは、修飾、例えば、そのアクセスで公開は、常にのstaticキーワードの前に書き込まれます。私。

public static ... 

ない:

static public ... 

EDIT:

EDIT2以下のコメントで示唆したように、より詳細を更新:上のデータを持つ、ContinueWithコール

+0

これはすべてポイントですしかし、データの最初のページ以上を読み込まなければならないという基本的な問題には対処できません。それをあなたの答えに加えることができますか? – StriplingWarrior

+0

@StriplingWarriorありがとう、私はより包括的に私の答えを拡大した。 –

+0

私はさらに改善を提案することができます: 'async/await'を使用している場合、通常は' ContinueWith'を避けることができます。 'var result = httpClient.GetAsync(nextUrl);を待ってください 'と言って、その直後にあなたの継続コードの残りを入れてください。この単純化されたフローは、 'failure'ブール値を追跡することを避けることができます。期待通りに行かないときに' break'、 'return'、または(私の意見では最良のオプション)'例外 'をスローすることができます。 – StriplingWarrior

関連する問題