如何循环使用C调用分页URL#的HttpClient从JSON结果下载所有网页(How to Loo

2019-09-27 12:19发布

我的第一个问题,所以请善待... :)

我使用的是C# HttpClient调用API乔布斯端点。

这里的端点: 乔布斯API端点(不需要钥匙,您可以点击)

这给了我JSON像这样。

{
  "count": 1117,
  "firstDocument": 1,
  "lastDocument": 50,
  "nextUrl": "\/api\/rest\/jobsearch\/v1\/simple.json?areacode=&country=&state=&skill=ruby&city=&text=&ip=&diceid=&page=2",
  "resultItemList": [
    {
      "detailUrl": "http:\/\/www.dice.com\/job\/result\/90887031\/918715?src=19",
      "jobTitle": "Sr Security Engineer",
      "company": "Accelon Inc",
      "location": "San Francisco, CA",
      "date": "2017-03-30"
    },
    {
      "detailUrl": "http:\/\/www.dice.com\/job\/result\/cybercod\/BB7-13647094?src=19",
      "jobTitle": "Platform Engineer - Ruby on Rails, AWS",
      "company": "CyberCoders",
      "location": "New York, NY",
      "date": "2017-04-16"
    }
 ]
}

我贴一个完整的JSON段,这样你可以在你的答案中使用它。 完整的结果是这里真的很长。

这里的是C#类。

using Newtonsoft.Json;
using System.Collections.Generic;

namespace MyNameSpace
{
    public class DiceApiJobWrapper
    {
        public int count { get; set; }
        public int firstDocument { get; set; }
        public int lastDocument { get; set; }
        public string nextUrl { get; set; }

        [JsonProperty("resultItemList")]
        public List<DiceApiJob> DiceApiJobs { get; set; }
    }

    public class DiceApiJob
    {
        public string detailUrl { get; set; }
        public string jobTitle { get; set; }
        public string company { get; set; }
        public string location { get; set; }
        public string date { get; set; }
    }
}

当我使用的HttpClient调用URL,并使用JSON.NET反序列化,我得到的数据传回正常。

下面是我从我的控制台应用程序的调用代码Main方法(因此static列表,我觉得这可以更好地重构??)

   private static List<DiceApiJob> GetDiceJobs()
    {
        HttpClient httpClient = new HttpClient();
        var jobs = new List<DiceApiJob>();

        var task = httpClient.GetAsync("http://service.dice.com/api/rest/jobsearch/v1/simple.json?skill=ruby")
          .ContinueWith((taskwithresponse) =>
          {
              var response = taskwithresponse.Result;
              var jsonString = response.Content.ReadAsStringAsync();
              jsonString.Wait();

              var result =  JsonConvert.DeserializeObject<DiceApiJobWrapper>(jsonString.Result);
              if (result != null)
              {
                  if (result.DiceApiJobs.Any())
                      jobs = result.DiceApiJobs.ToList();

                  if (result.nextUrl != null)
                  {
                      //
                      // do this GetDiceJobs again in a loop? How?? Any other efficient elegant way??
                  }
              }
          });
        task.Wait();

        return jobs;
    }

但现在,我如何检查是否有使用更多的就业机会nextUrl场? 我知道我可以检查,看它是否不为空,如果如果没有,这意味着有更多的就业机会拉下。

从我的调试,并通过步进结果

我该怎么做这个递归,没有挂,并与一些延误,所以我不越过API限制? 我想,我必须使用TPL(任务并行库),但我很困惑。

谢谢! 〜肖恩

Answer 1:

如果您担心您的应用程序的响应时间,想返回一些结果前,你真正了解从API的所有页/数据,你可以在一个循环中运行过程,也给它一个回调方法来执行,因为它得到各从API数据的页面。

下面是一个例子:

public class Program
{
    public static void Main(string[] args)
    {
        var jobs = GetDiceJobsAsync(Program.ResultCallBack).Result;
        Console.WriteLine($"\nAll {jobs.Count} jobs displayed");
        Console.ReadLine();
    }

    private static async Task<List<DiceApiJob>> GetDiceJobsAsync(Action<DiceApiJobWrapper> callBack = null)
    {
        var jobs = new List<DiceApiJob>();
        HttpClient httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("http://service.dice.com");
        var nextUrl = "/api/rest/jobsearch/v1/simple.json?skill=ruby";

        do
        {
            await httpClient.GetAsync(nextUrl)
                .ContinueWith(async (jobSearchTask) =>
                {
                    var response = await jobSearchTask;
                    if (response.IsSuccessStatusCode)
                    {
                        string jsonString = await response.Content.ReadAsStringAsync();
                        var result = JsonConvert.DeserializeObject<DiceApiJobWrapper>(jsonString);
                        if (result != null)
                        {
                            // Build the full list to return later after the loop.
                            if (result.DiceApiJobs.Any())
                                jobs.AddRange(result.DiceApiJobs.ToList());

                            // Run the callback method, passing the current page of data from the API.
                            if (callBack != null)
                                callBack(result);

                            // Get the URL for the next page
                            nextUrl = (result.nextUrl != null) ? result.nextUrl : string.Empty;
                        }
                    }
                    else
                    {
                        // End loop if we get an error response.
                        nextUrl = string.Empty;
                    }
                });                

        } while (!string.IsNullOrEmpty(nextUrl));
        return jobs;
    }


    private static void ResultCallBack(DiceApiJobWrapper jobSearchResult)
    {
        if (jobSearchResult != null && jobSearchResult.count > 0)
        {
            Console.WriteLine($"\nDisplaying jobs {jobSearchResult.firstDocument} to {jobSearchResult.lastDocument}");
            foreach (var job in jobSearchResult.DiceApiJobs)
            {
                Console.WriteLine(job.jobTitle);
                Console.WriteLine(job.company);
            }
        }
    }
}

注意,上述示例允许因为它是由所接收的回调方法来访问数据的每一页GetDiceJobsAsync方法。 在这种情况下,控制台,显示每个页面变得可用。 如果你不希望回调选项,你可以简单地传递没什么GetDiceJobsAsync

GetDiceJobsAsync它完成时也返回的所有作业。 所以,你可以选择作用于年底整个名单上GetDiceJobsAsync

至于达到API的限制,可以在循环中插入一个小的延迟,你重复循环权利之前。 但是,当我尝试了,我没有遇到的API限制我的要求,所以我不包括它的样本。



文章来源: How to Loop calls to Pagination URL in C# HttpClient to download all Pages from JSON results