Это своего рода учебное упражнение, но часть «весело». В основном, я пытаюсь разобрать цену в комнате «Балкон» (в настоящее время в $ 1039) в консольном приложении C #. URL-адрес:
У меня вышеуказанный url загружен штраф в:
var document = getHtmlWeb.Load(web_address);
Контейнер для цен на Балкон - это div с классом « col
» и является column-container clearfix
классом класса column-container clearfix
. Я думал, что все, что мне понадобится, - это очистить все div с классом за:
var lowest_price = document.DocumentNode.SelectNodes("//div[@class='col-bottom']");
а затем выберите 3-й узел, чтобы добраться до цены на балкон. Но переменная lower_price сохраняет значение null. Я знаю, что сам документ загружен, и я могу видеть внутри « col
», если я выберу « col
». Разве это дефис в col-bottom
который препятствует обнаружению этого div?
Любой альтернативный способ добраться до этого? Как я уже сказал, это в основном учебное упражнение. Но мне нужно создать некоторые пользовательские решения для мониторинга, которые требуют очистки экрана, и поэтому это не все просто весело.
Благодаря!
EDIT HTML-фрагмент, содержащий соответствующую информацию:
<div class="col">
<h2 data-cat-title="Balcony" class="uk-rate-title-OB"> Balcony </h2> <p> </p>
<div class="col-bottom">
<h3> From</h3>
<strong> $1,039.00* <span class="rate-compare-strike"> </span> </strong><a metacode="OB" href="#" class="select-btn">Select</a> </div>
</div>
Ничто не ошибочно относится к дефисам в именах или значениях атрибутов, которые являются действительными html, проблема с вашим источником заключается в том, что они используют javascript на клиенте для визуализации html, чтобы убедиться, что вы можете загрузить html-страницу, и вы заметите, что элементы, которые вы ищут, не существует.
Чтобы проанализировать такие страницы, на которых сначала нужно выполнить javascript, для этого вы можете использовать элемент управления веб-браузера, а затем передать html в HAP.
Вот простой пример того, как использовать элемент управления веб-браузером WinForms:
private void ParseSomeHtmlThatRenderedJavascript(){
var browser = new System.Windows.Forms.WebBrowser() { ScriptErrorsSuppressed = true };
string link = "yourLinkHere";
//This will be called when the web page loads, it better be a class member since this is just a simple demonstration
WebBrowserDocumentCompletedEventHandler onDocumentCompleted = new WebBrowserDocumentCompletedEventHandler((s, evt) => {
//Do your HtmlParsingHere
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(browser.DocumentText);
var someNode = doc.DocumentNode.SelectNodes("yourxpathHere");
});
//subscribe to the DocumentCompleted event using our above handler before navigating
browser.DocumentCompleted += onDocumentCompleted;
browser.Navigate(link);
}
Также вы можете взглянуть на Awesomium и некоторые другие встроенные элементы управления WebBrowser.
Также, если вы хотите запустить WebBrowser в консольном приложении, вот пример, если вы не получите его в виде окон Windows, этот пример с помощью этого SO ответит WebBrowser Control в новом потоке
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HtmlAgilityPack;
namespace ConsoleApplication276
{
// a container for a url and a parser Action
public class Link
{
public string link{get;set;}
public Action<string> parser { get; set; }
}
public class Program
{
// Entry Point of the console app
public static void Main(string[] args)
{
try
{
// download each page and dump the content
// you can add more links here, associate each link with a parser action, as for what data should the parser generate create a property for that in the Link container
var task = MessageLoopWorker.Run(DoWorkAsync, new Link() {
link = "google.com",
parser = (string html) => {
//do what ever you need with hap here
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
var someNodes = doc.DocumentNode.SelectSingleNode("//div");
} });
task.Wait();
Console.WriteLine("DoWorkAsync completed.");
}
catch (Exception ex)
{
Console.WriteLine("DoWorkAsync failed: " + ex.Message);
}
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
// navigate WebBrowser to the list of urls in a loop
public static async Task<Link> DoWorkAsync(Link[] args)
{
Console.WriteLine("Start working.");
using (var wb = new WebBrowser())
{
wb.ScriptErrorsSuppressed = true;
TaskCompletionSource<bool> tcs = null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (s, e) =>
tcs.TrySetResult(true);
// navigate to each URL in the list
foreach (var arg in args)
{
tcs = new TaskCompletionSource<bool>();
wb.DocumentCompleted += documentCompletedHandler;
try
{
wb.Navigate(arg.link.ToString());
// await for DocumentCompleted
await tcs.Task;
// after the page loads pass the html to the parser
arg.parser(wb.DocumentText);
}
finally
{
wb.DocumentCompleted -= documentCompletedHandler;
}
// the DOM is ready
Console.WriteLine(arg.link.ToString());
Console.WriteLine(wb.Document.Body.OuterHtml);
}
}
Console.WriteLine("End working.");
return null;
}
}
// a helper class to start the message loop and execute an asynchronous task
public static class MessageLoopWorker
{
public static async Task<Object> Run(Func<Link[], Task<Link>> worker, params Link[] args)
{
var tcs = new TaskCompletionSource<object>();
var thread = new Thread(() =>
{
EventHandler idleHandler = null;
idleHandler = async (s, e) =>
{
// handle Application.Idle just once
Application.Idle -= idleHandler;
// return to the message loop
await Task.Yield();
// and continue asynchronously
// propogate the result or exception
try
{
var result = await worker(args);
tcs.SetResult(result);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
// signal to exit the message loop
// Application.Run will exit at this point
Application.ExitThread();
};
// handle Application.Idle just once
// to make sure we're inside the message loop
// and SynchronizationContext has been correctly installed
Application.Idle += idleHandler;
Application.Run();
});
// set STA model for the new thread
thread.SetApartmentState(ApartmentState.STA);
// start the thread and await for the task
thread.Start();
try
{
return await tcs.Task;
}
finally
{
thread.Join();
}
}
}
}