2017-03-24 70 views
1

我目前正在嘗試使用其公共API獲取大量關於維基百科以外的視頻遊戲的數據。我已經得到了一些方法。我目前可以獲得我需要的所有pageid及其相關文章title。但後來我需要獲得他們的唯一標識符(Qxxxx,其中x是數字),這需要相當長一段時間...可能是因爲我必須爲每個標題(有22031)進行單個查詢,或者因爲我不瞭解Wikipedia查詢。當製作許多Http請求時,緩衝區大小不足或隊列滿了

所以我想「爲什麼不一次只做多個查詢?」所以我開始研究這個問題,但我在標題中遇到了這個問題。程序運行一段時間後(通常3-4分鐘)大約一分鐘過去,然後應用程序崩潰,標題中出現錯誤。我想這是因爲我的做法是隻壞:

ConcurrentBag<Entry> entrybag = new ConcurrentBag<Entry>(entries); 
Console.WriteLine("Getting Wikibase Item Ids..."); 
Parallel.ForEach<Entry>(entrybag, (entry) => 
{ 
    entry.WikibaseItemId = GetWikibaseItemId(entry).Result; 
}); 

這裏是調用的方法:

async static Task<String> GetWikibaseItemId(Entry entry) 
{ 
    using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate })) 
    { 
     client.BaseAddress = new Uri("https://en.wikipedia.org/w/api.php"); 
     entry.Title.Replace("+", "Plus"); 
     entry.Title.Replace("&", "and"); 
     String queryString = "?action=query&prop=pageprops&ppprop=wikibase_item&format=json&redirects=1&titles=" + entry.Title; 
     HttpResponseMessage response = await client.GetAsync(queryString); 

     response.EnsureSuccessStatusCode(); 

     String result = response.Content.ReadAsStringAsync().Result; 
     dynamic deserialized = JsonConvert.DeserializeObject(result); 
     String data = deserialized.ToString(); 
     try 
     { 
      if (data.Contains("wikibase_item")) 
      { 
       return deserialized["query"]["pages"]["" + entry.PageId + ""]["pageprops"]["wikibase_item"].ToString(); 
      } 
      else 
      { 
       return "NONE"; 
      } 
     } 
     catch (RuntimeBinderException) 
     { 
      return "NULL"; 
     } 
     catch (Exception) 
     { 
      return "ERROR"; 
     } 
    } 
} 

和公正的良好措施,這裏是入口類:

public class Entry 
{ 
    public EntryCategory Category { get; set; } 
    public int PageId { get; set; } 
    public String Title { get; set; } 
    public String WikibaseItemId { get; set; } 
} 

任何人都可能幫忙嗎?我只需要改變我如何查詢或其他東西?

+0

將同時運行的查詢數量限制爲合理數量,如10,而不是22k – dlatikay

+0

崩潰是因爲服務器不喜歡查詢。通過將查詢放入網頁的網址來手動嘗試查詢。你的申請只是3-4分鐘後超時。如果您獲得文章的標題,則還應該能夠同時獲取該網址。然後通過URL檢索文章。 – jdweng

+0

@dlatikay我會試試這個! – OmniOwl

回答

1

從一個進程並行啓動大約22000個http請求太多了。如果您的機器具有無限的資源和互聯網連接帶寬,這將接近拒絕服務攻擊。

您看到的是TCP/IP端口耗盡或隊列爭用。要解決它,請以較小的塊處理數組,例如獲取10個項目,並行處理這些數據,然後獲取下一個數據項,等等。

具體Wikimedia sites have a recommendation以串行方式處理請求:

沒有硬盤和讀取請求快速限制,但我們要求你體諒,儘量不採取現場下來。如果您確實危及其網站的穩定性,大多數系統管理員保留無條件地阻止您的權利。

如果您以串聯方式而不是並行方式發送請求(即在發送新請求之前等待一個請求完成,以至於您從未同時發送多個請求),那麼您應該一定很好。

務必檢查他們的API服務條款,以瞭解是否有多少並行請求符合要求。

+0

是的,我試圖通讀他們,看看我能做什麼,但你是對的。這接近DDOS攻擊哈哈。我改變了它,以便更少的請求現在並行運行。但是我應該改變它以像你說的一樣獲得多個ID。 – OmniOwl

+0

@Tgr在評論中指出,一些參數是多值參數。 'titles' [是這樣一個參數](https://www.mediawiki.org/wiki/API:Query#Title_normalization)。所以甚至可以在一個請求中組合多個標題的查詢。 – dlatikay

相關問題