tags:

views:

63

answers:

2

Want to grab list of players from http://www.atpworldtour.com/Rankings/Singles.aspx

There is a table with class "bioTableAlt", we have to grab all the <tr> after the first one (class "bioTableHead"), which is used for table heading.

Wanted content looks like:

<tr class="oddRow">
 <td>2</td>
 <td>
  <a href="/Tennis/Players/Top-Players/Novak-Djokovic.aspx">Djokovic, Novak</a>
  (SRB)
 </td>
 <td>
  <a href="/Tennis/Players/Top-Players/Novak-Djokovic.aspx?t=rb">6,905</a>
 </td>
 <td>0</td>
 <td>
  <a href="/Tennis/Players/Top-Players/Novak-Djokovic.aspx?t=pa&m=s">21</a>
 </td>
</tr>
<tr>
 <td>3</td>
 <td>
  <a href="/Tennis/Players/Top-Players/Roger-Federer.aspx">Federer, Roger</a>
  (SUI)
  </td>
 <td>
  <a href="/Tennis/Players/Top-Players/Roger-Federer.aspx?t=rb">6,795</a>
 </td>
 <td>0</td>
 <td>
  <a href="/Tennis/Players/Top-Players/Roger-Federer.aspx?t=pa&m=s">21</a>
 </td>
</tr>

I think the best idea is to create an array(), make each <tr> an unique row and throw final code to the list.txt file, like:

Array (
 [2] => stdClass Object (
    [name] => Djokovic, Novak
    [country] => SRB
    [rank] => 6,905
 )
 [3] => stdClass Object (
    [name] => Federer, Roger
    [country] => SUI
    [rank] => 6,795
 )
)

We're parsing each <tr>:

  • [2] is a number from first <td>
  • [name] is text of the link inside second <td>
  • [country] is a value between (...) in second <td>
  • [rank] is the text of the link inside third <td>

In final file list.txt should contain an array() with ~100 IDS (we are grabbing the page with first 100 players).

Additionally, will be amazing, if we make a small fix for each [name] before adding it to an array() - "Federer, Roger" should be converted to "Roger Federer" (just catch the word before comma, throw it to the end of the line).

Thanks.

+1  A: 

SimpleHTMLDOM will make this very easy for you.

The first few lines would look something like this (untested):

// Create DOM from URL or file
$html = file_get_html('http://www.atpworldtour.com/Rankings/Singles.aspx');

// Find all images 
foreach($html->find('table[id=bioTableAlt] tr[class!=bioTableHead]') as $element) 
    {

    }

(not sure about the tr[class!=bioTableHead], if it doesn't work, try a simple tr)

Pekka
Will try, actually I want only text and no images.
Happy
Suggested third party alternatives that actually use DOM instead of String Parsing: [phpQuery](http://code.google.com/p/phpquery/), [Zend_Dom](http://framework.zend.com/manual/en/zend.dom.html), [QueryPath](http://querypath.org/) and [FluentDom](http://www.fluentdom.org).
Gordon
@Gordon you totally have a point, as always. Haven't looked at phpQuery before, that one looks like it could become my new favourite :)
Pekka
@Pekka, please tell how to catch different <td> with SimpleHTMLDOM, like :nth-child(1) a {}
Happy
@Ignatz see http://simplehtmldom.sourceforge.net/manual.htm "How to traverse the DOM tree?"
Pekka
+1  A: 

Below is how to do it with PHP's native DOM extension. It should get you halfway to where you want to go.

The page is quite broken in terms of HTML validity and that makes loading with DOM somewhat tricky. Normally, you can use load() to load a page directly. But since the HTML is quite broken, I loaded the page into a string first and used the loadHTML method instead, because it handles broken HTML better.

Also, there is only one table at that page: the ranking table. The scoreboards are loaded via Ajax once the page loaded, so their HTML will not show up in the source code when you load it with PHP. So you can simply grab all TR elements and iterate over them.

libxml_use_internal_errors(TRUE);
$dom = new DOMDocument;
$dom->loadHTML(
    file_get_contents('http://www.atpworldtour.com/Rankings/Singles.aspx'));
libxml_clear_errors();

$rows = $dom->getElementsByTagName('tr');
foreach($rows as $row) {
    foreach( $row->childNodes as $cell) {
        echo trim($cell->nodeValue);
    }
}

This would output all table cell contents. It should be trivial to add those to an array and/or to write them to file.

Gordon
Thanks for your time.
Happy