Я использую Abot таким образом, что у меня есть приложение WPF, которое отображает элемент управления браузером (CefSharp). Пользователь входит в систему, и любая возможная пользовательская аутентификация, используемая сайтом, будет работать при сканировании так же, как если бы пользователь фактически просматривал сайт.
Таким образом, когда я сканирую, я хочу использовать этот элемент управления браузером, чтобы сделать запрос и просто вернуть данные страницы. Поэтому я реализовал свой собственный PageRequester, полный список ниже.
Проблема в том, что с CefSharp, как и с другими элементами управления браузера, невозможно получить HttpWebRequest/Response, связанный с CrawlPage. Без установки этих двух свойств Abot не продолжит сканирование.
Есть ли что-то, что я могу сделать, чтобы обойти эту проблему?
Список кодов:
using Abot.Core;
using Abot.Poco;
using CefSharp.Wpf;
using System;
using System.Net;
using System.Text;
using System.Threading;
public class CefPageRequester : IPageRequester
{
private MainWindowDataContext DataContext;
private ChromiumWebBrowser ChromiumWebBrowser;
private CrawlConfiguration CrawlConfig;
private volatile bool _navigationCompleted;
private string _pageSource;
public CefPageRequester(MainWindowDataContext dataContext, ChromiumWebBrowser chromiumWebBrowser, CrawlConfiguration crawlConfig)
{
this.DataContext = dataContext;
this.ChromiumWebBrowser = chromiumWebBrowser;
this.CrawlConfig = crawlConfig;
this.ChromiumWebBrowser.FrameLoadEnd += ChromiumWebBrowser_FrameLoadEnd;
}
public CrawledPage MakeRequest(Uri uri)
{
return this.MakeRequest(uri, cp => new CrawlDecision() { Allow = true });
}
public CrawledPage MakeRequest(Uri uri, Func<CrawledPage, CrawlDecision> shouldDownloadContent)
{
if (uri == null)
throw new ArgumentNullException("uri");
CrawledPage crawledPage = new CrawledPage(uri);
try
{
//the browser control is bound to the address of the data context,
//if we set the address directly it breaks for some reason, although it's a two way binding.
this.DataContext.Address = uri.AbsolutePath;
crawledPage.RequestStarted = DateTime.Now;
crawledPage.DownloadContentStarted = crawledPage.RequestStarted;
while (!_navigationCompleted)
Thread.CurrentThread.Join(10);
}
catch (WebException e)
{
crawledPage.WebException = e;
}
catch
{
//bad luck, we should log this.
}
finally
{
//TODO must add these properties!!
//crawledPage.HttpWebRequest = request;
//crawledPage.HttpWebResponse = response;
crawledPage.RequestCompleted = DateTime.Now;
crawledPage.DownloadContentCompleted = crawledPage.RequestCompleted;
if (!String.IsNullOrWhiteSpace(_pageSource))
crawledPage.Content = this.GetContent("UTF-8", _pageSource);
_navigationCompleted = false;
_pageSource = null;
}
return crawledPage;
}
private void ChromiumWebBrowser_FrameLoadEnd(object sender, CefSharp.FrameLoadEndEventArgs e)
{
if (!e.IsMainFrame)
return;
this.ChromiumWebBrowser.Dispatcher.BeginInvoke(
(Action)(() =>
{
_pageSource = this.ChromiumWebBrowser.GetSourceAsync().Result;
_navigationCompleted = true;
}));
}
private PageContent GetContent(string charset, string html)
{
PageContent pageContent = new PageContent();
pageContent.Charset = charset;
pageContent.Encoding = this.GetEncoding(charset);
pageContent.Text = html;
pageContent.Bytes = pageContent.Encoding.GetBytes(html);
return pageContent;
}
private Encoding GetEncoding(string charset)
{
Encoding e = Encoding.UTF8;
if (charset != null)
{
try
{
e = Encoding.GetEncoding(charset);
}
catch { }
}
return e;
}
}
Вопрос также можно сформулировать так: как избежать создания HttpWebResponse из потока? Что кажется невозможным, учитывая, что MSDN говорит а>:
Никогда не следует напрямую создавать экземпляр класса HttpWebResponse. Вместо этого используйте экземпляр, возвращаемый вызовом HttpWebRequest.GetResponse.
Мне пришлось бы фактически опубликовать запрос, чтобы получить ответ, чего я хочу избежать, имея элемент управления веб-браузером.