Advanced HTML Agility Pack useage

html-agility-pack screen-scraping

Question

I am pretty new to the HTML Agility Pack so I need some help with where to go next. I can do some simple things like pull a value from an href (knowing the url string I was looking for) and I can pull like the value in a span based on a specific class that was being used. But I do not understand how to use the HTML Agility Pack in a situation where there are a ton of or tags an thre is not one real solid anchor to tie to?

Here is an actual chunk of code I am scraping through. I placed dummy data in the cells to demonstrate what I am looking for.

What is the best way to extract the following: 1.) Company Name? 2.) Phone Number? 3.) Email Address?

HTML....

<td>
    <!-- Company Info -->
    <table cellpadding="0" cellspacing="0" border="0">
        <tr>
            <td class="black">
                <table cellspacing="1" cellpadding="0" border="0" width="370">
                    <tr>

                        <th>COMPANY NAME</th>
                    </tr>
                    <tr>
                        <td class="search">

                            <table cellpadding="5" cellspacing="0" border="0" width="100%">
                                <tr>
                                    <td>
                                        <table cellpadding="1" cellspacing="0" border="0" width="100%">

                                            <tr>
                                            <td colspan="2" align="center">Un-needed Links...</td>
                                            </tr>
                                            <tr>
                                                <td align="center" colspan="2"><hr></td>

                                            </tr>
                                            <tr>
                                                <td align="right" nowrap><b><font color="FF0000">Contact Person&nbsp;<img src="/images/icon_contact.gif" align="absmiddle">&nbsp;:</font></b></td>
                                                <td align="left" width="100%">&nbsp;Judy Smith</td>
                                            </tr>
                                            <tr>
                                                <td align="right" nowrap><b><font color="FF0000">Phone Number&nbsp;<img src="/images/icon_phone.gif" align="absmiddle">&nbsp;:</font></b></td>

                                                <td align="left" width="100%">&nbsp;555-555-5555</td>
                                            </tr>

                                            <tr>
                                                <td align="right" nowrap><b><font color="FF0000">E-mail Address&nbsp;<img src="/images/icon_email.gif" align="absmiddle">&nbsp;:</font></b></td>
                                                <td align="left" width="100%">&nbsp;<a HREF="mailto:judy.smith@companyname.com">judy.smith@companyname.com</a></td>
                                            </tr>
                                            <tr>

                                                <td align="center" colspan="2"><hr></td>
                                            </tr>
                                            <tr>
                                                <td align="right" nowrap><b><font color="FF0000">Home Office Location&nbsp;<img src="/images/icon_home.gif" align="absmiddle">&nbsp;:</font></b></td>
                                                <td align="left" width="100%">&nbsp;ATLANTA, GA</td>
                                            </tr>
                                            <tr>

                                                <td align="right" nowrap><b><font color="FF0000">Home Office Phone&nbsp;<img src="/images/icon_home.gif" align="absmiddle">&nbsp;:</font></b></td>
                                                <td align="left" width="100%">&nbsp;555-555-5555</td>
                                            </tr>
                                            <tr>
                                                <td align="right" nowrap><b><font color="FF0000">Home Office Fax&nbsp;<img src="/images/icon_home.gif" align="absmiddle">&nbsp;:</font></b></td>
                                                <td align="left" width="100%">&nbsp;666-666-6666</td>

                                            </tr>
                                            <tr>
                                                <td align="center" colspan="2"><hr></td>
                                            </tr>
                                            <tr>
                                                <td align="right" nowrap><b><font color="FF0000">Broker MC Number&nbsp;<img src="/images/icon_number.gif" align="absmiddle">&nbsp;:</font></b></td>
                                                <td align="left" width="100%">&nbsp;123456</td>

                                            </tr>
                                            <tr>
                                                <td align="right" nowrap><b><font color="FF0000">Carrier MC Number&nbsp;<img src="/images/icon_number.gif" align="absmiddle">&nbsp;:</font></b></td>
                                                <td align="left" width="100%">&nbsp;654321</td>
                                            </tr>

                                        </table>
                                    </td>

                                </tr>
                            </table>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>
    <br>

    <!-- Starting Point -->
    <table cellpadding="0" cellspacing="0" border="0">
        <tr>
            <td class="black">
                <table cellspacing="1" cellpadding="0" border="0" width="370">
                    <tr>
                        <th>Starting Point</th>
                        <th>Available</th>

                    </tr>
                    <tr>
                        <td class="search" width="270">&nbsp;<b>ABBEVILLE, GA&nbsp;</b></td>
                        <td class="search" align="center" width="100"><span style="color: forestgreen">&nbsp;1/5/11&nbsp;</span></td>
                    </tr>
                </table>
            </td>
        </tr>

    </table>
    <br>
    <!-- Destination Point -->
    <table cellpadding="0" cellspacing="0" border="0">
        <tr>
            <td class="black">
                <table cellspacing="1" cellpadding="0" border="0" width="370">
                    <tr>
                        <th>Destination Point</th>

                        <th>Direction</th>
                    </tr>
                    <tr>
                        <td class="search" width="270">&nbsp;<b>ATLANTA, GA&nbsp;</b></td>
                        <td class="search" align="center" width="100"><span style="color: FF0000">&nbsp;&nbsp;</span></td>
                    </tr>
                </table>
            </td>

        </tr>
    </table>
    <br>
    <!-- Truck Details -->
    <table cellpadding="0" cellspacing="0" border="0">
        <tr>
            <td class="black">
                <table cellspacing="1" cellpadding="0" border="0" width="370">
                    <tr>

                        <th>Truck Details</th>
                    </tr>
                    <tr>
                        <td class="search">
                            <table cellpadding="5" cellspacing="0" border="0">
                                <tr>
                                    <td>
                                        <table cellpadding="0" cellspacing="0" border="0">

                                            <tr>
                                                <td align="right"><b>Date Posted&nbsp;:</b></td>
                                                <td align="left">&nbsp;&nbsp;1/5/2011 10:34:48 AM</td>
                                            </tr>
                                            <tr>
                                                <td align="right"><b>Quantity&nbsp;:</b></td>

                                                <td align="left">&nbsp;&nbsp;1</td>
                                            </tr>
                                            <tr>
                                                <td align="right"><b>Equipment Type&nbsp;:</b></td>
                                                <td align="left">&nbsp;&nbsp;FT</td>
                                            </tr>
                                            <tr>

                                                <td align="right"><b>Load Size&nbsp;:</b></td>
                                                <td align="left">&nbsp;&nbsp;Full</td>
                                            </tr>
                                            <tr>
                                                <td align="right" valign="top"><b>Special Information&nbsp;:</b></td>
                                                <td align="left">&nbsp;&nbsp;</td>

                                            </tr>
                                        </table>
                                    </td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                </table>
            </td>

        </tr>
    </table>
    <br>
</td>

....More HTML

Accepted Answer

Well, you have to understand XPATH to really take advandage of the HTML agility pack scraping capabilities :-) You can google on "XPATH examples" to start with.

Focusing on the screen-scraping question, the tricky part is to select what you think is the most discriminant xpath expression for the information you want to get. Most of the time, there is not only one solution, and you must be prepared to update your code to stick with the target site HTML evolution.

So it's a trade off between very simple expressions with a risk that they match unwanted texts, and too discriminant expressions, not tolerant with evolutions in the scraped HTML, with a risk that they match nothing.

As for your specific text, this is a good real world example, and here is a code that does it:

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(yourText);

string companyName = doc.DocumentNode.SelectSingleNode("/td/table/tr/td/table/tr/th").InnerText;
Console.WriteLine("company name=" + companyName);

// another way
companyName = doc.DocumentNode.SelectSingleNode("//td[@class='black']/table/tr/th").InnerText;
Console.WriteLine("company name=" + companyName);

// a more advanced XPATH expression, means
// "Select a TD tag anywhere in the doc that has a preceding sibling of TD type with a B chid, with a FONT child with inner text starting with 'Phone Number'"
string phoneNumber = doc.DocumentNode.SelectSingleNode("//td[starts-with(preceding-sibling::td/b/font/text(), 'Phone Number')]").InnerText;
Console.WriteLine("phone Number=" + phoneNumber);

// same kind of story but go down the next A tag
string email = doc.DocumentNode.SelectSingleNode("//td[starts-with(preceding-sibling::td/b/font/text(), 'E-mail')]/a").InnerText;
Console.WriteLine("email=" + email);

PS: please note the HTML Agility Pack always expect tags used in XPATH expressions to be lowercase, even if they're not in the original HTML text.

As you see, the company name is retrieved here using two different expressions. They both work on the sample, but the first one will not resist if a new tag is added anywhere in the middle. The second one is more future-proof but is based on a CSS class tag that also may change. It's always a trade-off.

The phone number & email are similar but show the power of XPATH.




Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why