まず、このような素晴らしいコミュニティに感謝します。ここでの質問と回答から多くのことを学びました。これはSOに関する私の最初の質問なので、優しくしてください:)
わかりましたが、まず最初に:
-最初のコード バージョン:
private async void buttonWebScrap_Click(object sender, EventArgs e)
{
ClickLink("/ptk/sun/core/cookie/CookiesHandler.accept");
await Task.Delay(750);
if (_backgroundTaskRunning || !ClickLink("msisdn-change")) return;
_backgroundTaskRunning = true;
await LongTaskAsync();
}
private async Task LongTaskAsync()
{
const string previous = "msisdn-pool-prev";
const string next = "msisdn-pool-next";
var tempNumbers = new List<object>();
while (true)
{
await Task.Delay(750);
var document = webBrowser.DocumentText;
var htmlDoc = new HtmlAgilityPack.HtmlDocument();
htmlDoc.LoadHtml(document);
var numbers = htmlDoc.DocumentNode.SelectNodes("//a[starts-with(@id, 'msisdn')]");
tempNumbers.AddRange(from number in numbers
where number.Id != previous && number.Id != next
select number.InnerText.RemoveEnters().RemoveSpaces().ReplaceSpecificChars());
tempNumbers.Add("-------------------------");
if (tempNumbers.Count >= 24)
{
listBoxNumbers.Items.AddRange(tempNumbers.ToArray());
tempNumbers.Clear();
}
if (ClickLink(next) == false)
{
break;
}
}
}
private bool ClickLink(string linkId)
{
if (webBrowser.Document != null)
{
var elementById = webBrowser.Document.GetElementById(linkId);
if (elementById != null)
{
elementById.InvokeMember("click");
}
else
{
return false;
}
if (webBrowser.Document.Window != null)
{
webBrowser.Document.Window.ScrollTo(0, 480);
}
}
else
{
return false;
}
return true;
}
-2 番目のコード バージョン:
private void MainForm_Load(object sender, EventArgs e)
{
_webBrowserDocuments = new ConcurrentQueue<string>();
_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
_progress = new Progress<string>();
_progress.ProgressChanged += (o, s) => _objects.Add(s);
_objects = new BindingList<string>();
listBoxNumbers.DataSource = _objects;
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
WebBrowserEmulation.Delete();
}
private async void buttonWebScrap_Click(object sender, EventArgs e)
{
await WebBrowserClickLinkAsync("/ptk/sun/core/cookie/CookiesHandler.accept");
if (_backgroundTaskRunning || !(await WebBrowserClickLinkAsync("msisdn-change"))) return;
await Task.Delay(5000);
var cts = new CancellationTokenSource();
await WebBrowserDocumentDownloadAsync(cts);
await DocumentParseAsync(_progress, cts);
_backgroundTaskRunning = true;
}
private async Task DocumentParseAsync(IProgress<string> progress, CancellationTokenSource cts)
{
await Task.Factory.StartNew(() =>
{
while (true)
{
string tempDocument;
if (_webBrowserDocuments.TryDequeue(out tempDocument))
{
var htmlDoc = new HtmlAgilityPack.HtmlDocument();
htmlDoc.LoadHtml(tempDocument);
var numbers = htmlDoc.DocumentNode.SelectNodes("//a[starts-with(@id, 'msisdn')]");
foreach (var number in numbers.Where(number => number.Id != Previous && number.Id != Next).
Select(x => x.InnerText.RemoveEnters().RemoveSpaces().ReplaceSpecificChars()))
{
progress.Report(number);
}
progress.Report("-------------------------");
}
if (cts.IsCancellationRequested)
{
break;
}
}
}, cts.Token);
}
private async Task WebBrowserDocumentDownloadAsync(CancellationTokenSource cts)
{
await Task.Factory.StartNew(async () =>
{
while (true)
{
await Task.Delay(1000);
_webBrowserDocuments.Enqueue(webBrowser.DocumentText);
if (await WebBrowserClickLinkAsync(Next)) continue;
cts.Cancel();
break;
}
}, new CancellationToken(), TaskCreationOptions.None, _uiScheduler);
}
private async Task<bool> WebBrowserClickLinkAsync(string linkId)
{
return await Task.Factory.StartNew(() =>
{
if (webBrowser.Document != null)
{
var elementById = webBrowser.Document.GetElementById(linkId);
if (elementById != null)
{
elementById.InvokeMember("click");
}
else
{
return false;
}
if (webBrowser.Document.Window != null)
{
webBrowser.Document.Window.ScrollTo(0, 480);
}
}
else
{
return false;
}
return true;
}, new CancellationToken(), TaskCreationOptions.None, _uiScheduler);
}
最初はすべて問題なく動作していますが、約 500 の数値を Web スクレイピングした後、「GUI」が少し遅くなります。それが async/await パターンの「悪い」理解によるものなのか、それとも他の何かによるものなのかはわかりません。このタスクには 2 番目のバージョンの方が適していると思いましたが、それでもまだ遅いです :/. 誰かがこれで私を助けることができますか?
Web クライアントの代わりに Web ブラウザ コントロールを使用しているのはなぜですか? はるかに簡単になることはわかっていますが、Webスクレイピング元のサイトは(私が見ているように)Java(jsessionId)+ ajaxで作成されており、「適切な」リンクはありません。
さらに詳細が必要な場合は、書いてください ;)
前もって感謝します。
編集:
2 番目のバージョンは、タスク (またはタスク) を返すメソッドを使用して、MainForm からの現在の SynchronizationContext での待機を簡素化します (そのうちの 2 つだけ)。
最初のバージョンは、await/async を使用する最初のアプローチでした (LongTaskAsync() メソッドが await Task.Delay() と非同期であることがわかるように)。
これは完成したコードです (SynchronizationContext の取得、ListBox.DataSource を BindList に設定するなどの考えはありません)。