HtmlAgilityPack dlaczego mam null w parsowaniu?

0

Mam taki błąd. Wcześniej działało a teraz takie coś mi wyskakuje. Może jest nałożone jakieś zabezpieczenie? Proszę o podpowiedź

System.NullReferenceException: „Odwołanie do obiektu nie zostało ustawione na wystąpienie obiektu.”

HtmlAgilityPack.HtmlNode.SelectSingleNode(...) zwrócił null.

kod programu

            string url = @"http://www.baza-firm.com.pl/?vm=zabrze&pg=2&b_szukaj=szukaj";
            HtmlWeb web = new HtmlWeb();

            var doc1 = web.Load(url);

            MessageBox.Show(doc1.ToString());
                

            var nazwa = doc1.DocumentNode.SelectSingleNode("//div/a/span[@itemprop='name']").InnerText; //tu blad
            var ulica = doc1.DocumentNode.SelectSingleNode("//div[@itemprop='streetAddress']").InnerText;
            var kod_pocztowy = doc1.DocumentNode.SelectSingleNode("//div/span[@itemprop='postalCode']").InnerText;
            var miejscowość = doc1.DocumentNode.SelectSingleNode("//div/span[@itemprop='addressLocality']").InnerText;
            var wojewodztwo = doc1.DocumentNode.SelectSingleNode("//div/span[@itemprop='addressRegion']").InnerText;
            var telefon = doc1.DocumentNode.SelectNodes("//div[@class='divSMV_tel1 clearBoth']");
            List<string> lista_tel = new List<string>();
            foreach (var node in telefon)
            {
                lista_tel.Add(node.InnerText);
            }

            MessageBox.Show("nazwa " + nazwa
                            + "\nkod pocztowy " + kod_pocztowy
                            + "\nulica " + ulica
                            + "\nkod pocztowy " + kod_pocztowy
                            + "\nmiejscowość " + miejscowość
                            + "\nwojewództwo " + wojewodztwo
                            + "\ntelefon " + lista_tel[0].ToString());
0

Masz pokręcone xpath.

0
HomoChemicus napisał(a):

Masz pokręcone xpath.
Co niby mam źle? Wcześniej działało teraz po żadnych zmianach nie działa a strona wygląda tek samo.
Tj. jest część HTML tej strony

<div id="wizidk_1006" class="mwiz_wyr">
<div class="divSMV_daneNazwabold">
<a class="wizLnk" href="http://www.baza-firm.com.pl/maszyny-i-urządzenia-górnicze/zabrze/dak-firma/pl/1006.html" target="_blank" title="DAK-Firma Zabrze">
<span class="przeppoz" itemprop="name">DAK-Firma</span> 
<span class="normalTxt">»</span></a></div>
<div class="smWizLp">.21</div>
<div class="marginTop10 divSMV_daneResztaBK">
<div class="telAddrBox" onclick="window.open('http://www.baza-firm.com.pl/maszyny-i-urządzenia-górnicze/zabrze/dak-firma/pl/1006.html','',''); return false" onmouseover="this.style.cursor='pointer'" itemscope="" itemprop="address" itemtype="http://schema.org/PostalAddress" style="cursor: pointer;"><div class="divSMV_ulica" itemprop="streetAddress">ul. Hermisza 15</div>
<div class="divSMV_kod">
<span itemprop="postalCode">41-800</span>&nbsp;
<span itemprop="addressLocality">Zabrze
</span></div>
<div class="smWizWoj">woj. 
<span itemprop="addressRegion">śląskie</span>
</div>
<div class="divSMV_tel1 clearBoth">
<div itemprop="telephone">tel. (32) 376 20 85</div>
<div itemprop="telephone">fax (32) 376 20 86</div>
</div><div class="smWizPikto">
<span class="pikto_txt" title="+5">więcej »</span>
</div></div>
<div class="smWizLogo">
<a href="http://www.dak-firma.pl/" title="DAK-Firma - http://www.dak-firma.pl/" target="_blank" rel="nofollow">
<img src="http://www.baza-firm.com.pl/firmy/1/1006/logo/1006_logo.gif?t=1149669268" data-src="http://www.baza-firm.com.pl/firmy/1/1006/logo/1006_logo.gif?t=1149669268" alt="DAK-Firma" class="borderNone lazyloaded" width="61" height="65"></a>
</div></div></div>
0

HtmlAguilityPack ma jakiś problem ze stroną. Zauważ, że nie zostaje zaciągnięty kod html. Tu ktoś miał podobny problem.

0

Jest inny sposób pobrania kodu HTML strony? Chyba, że jakoś można to inaczej zrobić w HtmlAguilityPack. Próbowałem też From Browser ale też nie działa. Ciekawy ten problem :)

0

To powinno zadziałać: Jedna z ostatnich odpowiedzi Daj znać czy ruszyło, bo tego nie testowałem

0

Znalazłem rozwiązanie, które podobno działa. Mam problem jednak z zaimplementowaniem go.

private void button2_ClickAsync(object sender, EventArgs e)
{
string url = @"http://www.baza-firm.com.pl/?vm=zabrze&pg=2&b_szukaj=szukaj";
var doc1 = new HtmlAgilityPack.HtmlDocument();

using (var client = new HttpClient())
{
    var resp = await client.GetAsync(url);
    MessageBox.Show(resp.StatusCode.ToString());
    var html = await resp.Content.ReadAsStringAsync();
    doc1.LoadHtml(html);
}


MessageBox.Show(doc1.DocumentNode.OuterHtml.ToString());
}

Mam taki błąd na słowie "await".

Operatora „await” można używać tylko wewnątrz metody asynchronicznej. Rozważ możliwość oznaczenia tej metody za pomocą modyfikatora „async” i zmiany zwracanego przez nią typu na „Task”.>

Pierwszy raz coś takiego widzę

0

Dodaj przed "void" "async" i będzie śmigać.
PS Teraz poprawnie parsuje stronę.

0

A może mi ktoś wytłumaczyć jak to teraz działa? Bardzo jestem zadowolony z tego, że mi to w końcu ruszyło ale chciałbym się nauczyć pisać podobne programy już sam lub też móc innym wytłumaczyć. Chodzi mi głównie o fragment "using (var client = new HttpClient()){..}"

       private async void  button2_ClickAsync(object sender, EventArgs e)
        {
            string url = @"http://www.baza-firm.com.pl/?vm=zabrze&pg=2&b_szukaj=szukaj";
            var doc1 = new HtmlAgilityPack.HtmlDocument();

            using (var client = new HttpClient())
            {
                var resp = await client.GetAsync(url);
               // MessageBox.Show(resp.StatusCode.ToString());
                var html = await resp.Content.ReadAsStringAsync();
                doc1.LoadHtml(html);
            }


            var nazwa = doc1.DocumentNode.SelectSingleNode("//span[@class='przeppoz']").InnerText;
            var ulica = doc1.DocumentNode.SelectSingleNode("//div[@itemprop='streetAddress']").InnerText;
            var kod_pocztowy = doc1.DocumentNode.SelectSingleNode("//div/span[@itemprop='postalCode']").InnerText;
            var miejscowość = doc1.DocumentNode.SelectSingleNode("//div/span[@itemprop='addressLocality']").InnerText;
            var wojewodztwo = doc1.DocumentNode.SelectSingleNode("//div/span[@itemprop='addressRegion']").InnerText;
            var telefon = doc1.DocumentNode.SelectNodes("//div[@class='divSMV_tel1 clearBoth']");
            List<string> lista_tel = new List<string>();
            foreach (var node in telefon)
            {
                lista_tel.Add(node.InnerText);
            }

            MessageBox.Show("nazwa " + nazwa
                            + "\nkod pocztowy " + kod_pocztowy
                            + "\nulica " + ulica
                            + "\nkod pocztowy " + kod_pocztowy
                            + "\nmiejscowość " + miejscowość
                            + "\nwojewództwo " + wojewodztwo
                            + "\ntelefon " + lista_tel[0].ToString());
        }
    }
0

Dzięki using(..){} nie musisz wywoływać client.Dispose(true).

0
HomoChemicus napisał(a):

Dodaj przed "void" "async" i będzie śmigać.
PS Teraz poprawnie parsuje stronę.

To najgorsza rada jaką możesz dać. W przypadku exceptiona nie będzie żadnego sensownego response.

W przypadku metod async trzeba używać Task lub wersji Task<T> inaczej to proszenie sie o kłopoty.

Ostatnio widziałem kod gdzie z WebApi były zwracane void i się geniusz dziwił dlaczego 500 nie dostaje... Tu będzie podobnie...

0

Tak jak napisał @HomoChemicus warto by to wydzielić, inaczej, prędzej czy później, najdzie Cię ochota żeby użyć tego jeszcze gdzieś, zrobisz await button2_ClickAsync(null, null) i przez przypadek odpalisz "Fire and forget".

0

Wyskakuje mi błąd "Błąd CS0021 Do wyrażenia typu „Task<string[,]>” nie można zastosować indeksowania przy użyciu konstrukcji []." =. Jak to powinno wyglądać teraz kod jeżeli chcę wyświetlić wynik bo tego "Task<>" trochę nie rozumiem.

   class nowa
    {
        public async Task<String[,]> co()
        {
            string url = @"http://www.baza-firm.com.pl/?vm=zabrze&pg=2&b_szukaj=szukaj";
            var htmlDoc = new HtmlAgilityPack.HtmlDocument();

            using (var client = new HttpClient())
            {
                var resp = await client.GetAsync(url);
                // MessageBox.Show(resp.StatusCode.ToString());
                string html = await resp.Content.ReadAsStringAsync();


                htmlDoc.LoadHtml(html);
            }
            var nazwa = htmlDoc.DocumentNode.SelectNodes("//div/a/span[@itemprop='name']");
            List<string> lista_nazwa = new List<string>();
            foreach (var node in nazwa)
            {
                lista_nazwa.Add(node.InnerText);
            }

            var telefon = htmlDoc.DocumentNode.SelectNodes("//div[@class='divSMV_tel1 clearBoth']");
            List<string> lista_tel = new List<string>();
            foreach (var node in telefon)
            {
                lista_tel.Add(node.InnerText);
            }

            String[,] tablica = new string[35, lista_nazwa.Count];

            for (int i = 0; lista_nazwa.Count > i; i++)
            {
                tablica[0, i] = lista_nazwa[i].ToString();
                tablica[1, i] = lista_tel[i].ToString();
            }

            return tablica;

        }
    }

        private void  button2_ClickAsync(object sender, EventArgs e)
        {
            nowa nw = new nowa();
            Task <String[,]> wynik_parsowania = nw.co();
            //MessageBox.Show(wynik_parsowania[0,0]);
          string a =  wynik_parsowania[0, 0]; //blad

        }
0

Twoja funkcja co() (beznadziejna nazwa, zmień na jakąś sensowną) zwraca Task<string[,]>, czyli tak naprawdę nie zwraca tablicy stringów, tylko taki specjalny obiekt związany z async/await. Wynika to z tego, że funkcja co() jest oznaczona jako async (bo awaituje asynchroniczne metody pochodzące z HttpClient).

W swojej funkcji button2_ClickAsync musisz użyć await:

nowa nw = new nowa();
var wynik_parsowania = await nw.co();
string a =  wynik_parsowania[0, 0];

I dodać słowo kluczowe async również do funkcji button2_ClickAsync (która pewnie miała być async, bo tak się nazywa, ale z jakichś powodów nie jest).

0

Dzięki :) a możesz mi jeszcze napisać gdzie mogę poczytać wyjaśnienia i sposób działania użytych tutaj metod w kodzie? Jakąś książkę lub artykuł w necie. Chcę to zrozumieć dokładnie żebym już nie musiał pytać i wiedzieć do czego można jeszcze to wykorzystać

0

Masz to ładnie wyłożone w C# 6.0 Kompletny przewodnik dla praktyków. Co do kodu, to zwracałbym obiekt z wynikami parsowania.

1 użytkowników online, w tym zalogowanych: 0, gości: 1