I'm trying to get a better understanding of PHP Simple HTML DOM and am kinda stuck on the following.
I am trying to retrieve information from one of my user pages by using the following code :
$dom = file_get_html('http://127.0.0.1/comments/top-commenters/');
foreach($dom->find('tr[id*=commenter]') as $result) {
print_r($result->innertext);
}
Which produces for each commenter profile ($result->innertext) the following :
<td class="Position"># 3 </td>
<td class="img" align="center">
<a href="/images/users/814ocnqlN6.jpg">
<img src="/images/users/814ocnqlN6.jpg" info="Image" border="0"/></a>
<a uid="814ocnqlN6"></td>
<td> <b>User 3.</b>
<div class="tiny">Most recent comments</div>
</td>
<td class="NumCredits"> 471 </td>
<td class="NumComments"> 5.439 </td>
<td class="PercUpVotes"> 93% </td>
Now if I would like to access within each result (same foreach loop) for example :
<td class="Position"># 3 </td>
And
<td class="NumComments"> 5.439 </td>
What would be the best way to accomplish this ?
Try:
$dom = file_get_html('http://127.0.0.1/comments/top-commenters/');
foreach($dom->find('tr[id*=commenter]') as $result) {
print_r($result->find('td.Position'));
print_r($result->find('td.NumComments'));
}
}
Related
I am scraping some values from a table but I have problem to get values from data-odd ("odds" and "odds best betrate" as Class) into td tags.
I will post code:
<tr class="first-row">
<td class="first-cell tl">
Kortrijk - St. Truiden
</td>
<td class="result">
3:0
</td>
<td class="odds best-betrate" **data-odd="1.72"**></td>
<td class="odds" **data-odd="3.61"**></td>
<td class="odds" **data-odd="4.76"**></td>
<td class="last-cell nobr date">20.02.2016</td>
</tr>
<tr class="strong">
<td class="first-cell tl">
Lokeren - Genk
</td>
<td class="result">
0:0
</td>
<td class="odds" **data-odd="3.11"**></td>
<td class="odds best-betrate" **data-odd="3.31"**></td>
<td class="odds" **data-odd="2.25"**></td>
<td class="last-cell nobr date">20.02.2016</td>
</tr>
I know how I can get values between tags and I got them using Simple HTML Dom, but I really don't know how I can get values about "data-odd. In my code you can see bold values that I want to get.
Thanks :)
EDIT: Now I got this result (see picture below):
enter image description here
I want that values together the others values, example:
21.02.2016
Waasland-Beveren - Anderlecht 1:0 5.96 4.20 1.51
21.02.2016
Waregem - KV Mechelen 2:3 1.83 3.71 3.98
Thanks Again!
EDIT2:
This is my code:
<?php
include('../simple_html_dom.php');
$html = file_get_html('http://www.betexplorer.com/soccer/belgium/jupiler-league/results/');
foreach($html->find('td') as $e) {
echo $e->innertext . '<br>';
}
foreach( $html->find('td[data-odd]') as $td )
{
echo $td->attr['data-odd'].PHP_EOL;
}
?>
As mentioned in the comments, data-odd is an attribute of node, so to retrieve its value with simple_html_dom you have to use this syntax:
foreach( $html->find('td[data-odd]') as $td )
{
echo $td->attr['data-odd'].PHP_EOL;
}
I'am using strip_tags function to fetch only required content but it fetches the whole data from a link
see the example code below i m using to fetch content from a link:
<?php
$a=fopen("http://example.com/","r");
$contents=stream_get_contents($a);
fclose($a);
$contents1=strtolower($contents);
$start='<div id="content">';
$start_pos=strpos($contents1,$start);
$first_trim=substr($contents1,$start_pos);
$stop='</div><!-- content -->';
$stop_pos=strpos($first_trim,$stop);
$second_trim=substr($first_trim,0,$stop_pos+6);
$second_trim = strip_tags($second_trim, '<div><table><tbody><tr><td><a><h2><h4>');
echo "<div>$second_trim</div>";
?>
here is the html code fetched in $second_trim:
<div><div id="content">
<div id="issuedescription"></div>
<h2 class="wsite-content-title" style="text-align:center;">download content<br /><font color="#f30519">table of content</font><br /> <font color="#f80117"> content </font></h2>
<h2>table of contents</h2>
<h4 class="tocsectiontitle">editorial</h4>
<h2 class="wsite-content-title" style="text-align:left;">technical note</h2>
<table class="tocarticle" width="100%">
<tr valign="top">
<td class="toctitle" width="95%" align="left">where are we at and where are we heading to? </td>
<td class="tocgalleys" width="5%" align="left">
pdf
</td>
</tr>
<tr>
<td class="tocauthors" width="95%" align="left">
sergio eduardo de paiva gonã§alves </td>
<td class="tocpages" width="5%" align="left">1-2</td>
</tr>
</table>
<div class="separator"></div>
h4 class="tocsectiontitle">some text here</h4>
<table class="tocarticle" width="100%">
<tr valign="top">
<td class="toctitle" width="95%" align="left">some text here</td>
<td class="tocgalleys" width="5%" align="left">
pdf
</td>
</tr>
<tr>
<td class="tocauthors" width="95%" align="left">
some text here, some text here, some text here, some text here, some text here, some text here </td>
<td class="tocpages" width="5%" align="left">3-10</td>
</tr>
</table>
<a target="_blank" rel="license" href="http://example.com/">
</a>
some text here<a rel="license" target="_blank" href="http://example.com/">example</a>.
</div></div>
Now my problem is i want to fetch a particular tag only, from the whole content like 2nd anchor from two of given below using strip_tag function
pdf
some text here
and 2nd header tag from two of given below:
<h2 class="wsite-content-title" style="text-align:center;">download content<br /><font color="#f30519">table of content</font><br /> <font color="#f80117"> content </font></h2>
<h2>table of contents</h2>
but strip tag function is either fetching all of them or none of them , So how can i make them identify to fetch the tag I want instead of fetching all the similar tags.If their is any better way to do this please share your ideas here !!
A regexp can do such a thing:
function handle_link($data) {
list($link, $attributes, $content) = $data;
$classes = preg_match('#class=[\'"]([^\'"]+)[\'"]#', $attributes, $match) ? preg_split('#\s+#', $match[1]) : array();
// If the link has the "file" class
if(in_array('file', $classes)) {
return $content; // only the internal content (like strip_tags would do)
// or you can return a new link:
// return '' . $content . '';
} else {
return $link; // all the link not filtered
}
}
$second_trim = strip_tags($second_trim, '<div><table><tbody><tr><td><h2><h4>');
$second_trim = preg_replace_callback('#<a([^>]*)>(.+)</a>#U', 'handle_link', $second_trim);
There is a html page, it contains a block:
<table class="tborder" cellpadding="6" cellspacing="1" border="0" width="100%" align="center">
<tr>
<td class="tcat" colspan="2">
Some regular text <span class="normal">the desired text 1</span>
</td>
</tr>
<tr>
<td class="alt1" colspan="2">
<span class="smallfont">link1, <i><b><font color="#006400">link2</font></b></i></span>
</td>
</tr>
</table>
Help me to parse with simple html dom library or a regular expression, so that would be deduced only here it is:
the desired text 1 <span class="smallfont">link1, <i><b><font color="#006400">link2</font></b></i></span>
If I do this:
<?
include 'simple_html_dom.php';
$html = file_get_html('http://some-url.com/power.html');
foreach($html->find('td[class="tcat"]') as $element1)
echo $element1. '<br>';
foreach($html->find('span[class="smallfont"]') as $element2)
echo $element2. '<br>';
?>
So, along with the necessary data also are displayed more similar elements that presents on the page. (with the same parameters 'td class="tcat"' and 'class="smallfont"')
I need that would be deduced only that:
the desired text 1 <span class="smallfont">link1, <i><b><font color="#006400">link2</font></b></i></span>
It's all about knowing css:
echo $html->find('td.tcat span', 0)->text();
echo $html->find('span.smallfont', 0);
//the desired text 1 <span class="smallfont">link1, <i><b><font color="#006400">link2</font></b></i></span>
I have something along the following lines in terms of HTML. I would like to extract the various contents of the table cells, however I discovered that there are some embedded divs occasionally in the cells and perhaps other oddities that I'm not sure of yet:
<p align="center">
<img src="some_image.gif" alt="Some Title">
</p>
<TABLE WIDTH=500 BORDER=1 class=textwhite ALIGN=center CELLPADDING=0 CELLSPACING=0>
<TR>
<TD colspan=4 ALIGN=center><b>Title</b></TD>
</TR>
<TR>
<TD ALIGN=center>Title</TD>
<TD ALIGN=center>date</TD>
<TD ALIGN=center>value</TD>
<TD ALIGN=center>value</TD>
</TR><TR>
<TD ALIGN=center>Title2</TD>
<TD ALIGN=center></TD>
<TD ALIGN=center><div class=redtext>----</div></TD>
<TD> </TD>
</TR><TR>
<TD ALIGN=center>Title3</TD>
<TD ALIGN=center><div class=yellowtext>value</div></TD>
<TD ALIGN=center><div class=redtext>value</div></TD>
<TD ALIGN=center>value<SUP>6</SUP></TD>
</TR><TR>
<TD ALIGN=center>Title4</TD>
<TD ALIGN=center><div class=bluetext>value</div></TD>
<TD ALIGN=center><div class=redtext>value</div></TD>
<TD> </TD>
</TR></TABLE>
<blockquote>
<p class="textstyle">
Text.
</p>
</blockquote>
My first impulse was to extract ALL element texts and just programmatically slice it up. I would watch for Title1, Title2, etc. to know when a row starts and then if a "----" is found meaning no value, just skip this row and move on. However, I realized that there is probably a better way of handling this with xpath directly.
How could this be solved with xpath so as to essentially give each cell's final child text content vs having to walk into each div if it exists? Or is there a more xpath like way to approach this?
Obviously I'm attempting to have the most flexible solution that will not be brittle if other unexpected elements crop up, even though they are unlikely.
The provided text isn't well-formed XML document, therefore XPath isn't applicable.
If you correct and covert it to a well-formed xml document as the one below, an expression like this might be useful:
/*/TABLE//TD//text()
or even:
//TABLE//TD//text()
Here is a wellformed XML document, constructed from the provided HTML:
<html>
<p align="center">
<img src="some_image.gif" alt="Some Title"/>
</p>
<TABLE WIDTH="500" BORDER="1" class="textwhite" ALIGN="center" CELLPADDING="0" CELLSPACING="0">
<TR>
<TD colspan="4" ALIGN="center">
<b>Title</b>
</TD>
</TR>
<TR>
<TD ALIGN="center">Title</TD>
<TD ALIGN="center">date</TD>
<TD ALIGN="center">value</TD>
<TD ALIGN="center">value</TD>
</TR>
<TR>
<TD ALIGN="center">Title2</TD>
<TD ALIGN="center"></TD>
<TD ALIGN="center">
<div class="redtext">----</div>
</TD>
<TD> </TD>
</TR>
<TR>
<TD ALIGN="center">Title3</TD>
<TD ALIGN="center">
<div class="yellowtext">value</div>
</TD>
<TD ALIGN="center">
<div class="redtext">value</div>
</TD>
<TD ALIGN="center">value
<SUP>6</SUP>
</TD>
</TR>
<TR>
<TD ALIGN="center">Title4</TD>
<TD ALIGN="center">
<div class="bluetext">value</div>
</TD>
<TD ALIGN="center">
<div class="redtext">value</div>
</TD>
<TD> </TD>
</TR>
</TABLE>
<blockquote>
<p class="textstyle"> Text. </p>
</blockquote>
</html>
So maybe you don't want to walk the divs, but here is my solution using lxml, which I highly recommend:
import re
from cStringIO import StringIO
from lxml import etree
def getTable(html, table_xpath, rows_xpath, cells_xpath):
"""Get a table on a webpage"""
parser = etree.HTMLParser()
# Build document tree and get table
root = etree.parse(StringIO(html), parser)
table = root.find(table_xpath)
if table == None:
print 'No table.'
return []
rows = table.findall(rows_xpath)
document = []
def cleanText(text):
"""Clean up text by replacing line breaks and tabs. """
return re.sub(r'[\r\n\t]+','',str(text).strip())
# iterate over the table rows and collect text from each cell.
for r in rows:
cells = r.findall(cells_xpath)
rowdata = []
for c in cells:
text = ''
it = c.itertext()
for i in it:
text += cleanText(i) + ' '
rowdata.append(text)
document.append(rowdata)
return document
html = """
<html><head><title></title></head><body>
<p align="center">
<img src="some_image.gif" alt="Some Title">
</p>
<TABLE WIDTH=500 BORDER=1 class=textwhite ALIGN=center CELLPADDING=0 CELLSPACING=0>
<TR>
<TD colspan=4 ALIGN=center><b>Title</b></TD>
</TR>
<TR>
<TD ALIGN=center>Title</TD>
<TD ALIGN=center>date</TD>
<TD ALIGN=center>value</TD>
<TD ALIGN=center>value</TD>
</TR><TR>
<TD ALIGN=center>Title2</TD>
<TD ALIGN=center></TD>
<TD ALIGN=center><div class=redtext>----</div></TD>
<TD> </TD>
</TR><TR>
<TD ALIGN=center>Title3</TD>
<TD ALIGN=center><div class=yellowtext>value</div></TD>
<TD ALIGN=center><div class=redtext>value</div></TD>
<TD ALIGN=center>value<SUP>6</SUP></TD>
</TR><TR>
<TD ALIGN=center>Title4</TD>
<TD ALIGN=center><div class=bluetext>value</div></TD>
<TD ALIGN=center><div class=redtext>value</div></TD>
<TD> </TD>
</TR></TABLE>
</body>
</html>
"""
tp = "//table[#width='500']"
rt = "tr"
cp = "td[#align='center']"
doc = getTable(html, tp, rt, cp)
print repr(doc)
I believe that your program is going to run into many problems as the input data is manipulated -- what if the case of 'title' changes, or there is a typo?
It's not really possible to make a rigorous solution to scraping someone else's website, as they can at no notice completely change everything. Better is normally to write tolerant and flexible code that at least tries to verify that its output is sane. In this case it's probably best to iterate over the results of '//table/tr', then inside this loop, process the td elements:
import lxml.etree
tree = lxml.etree.fromstring("<table><tr><td>test</td></tr><tr><td><div>test2</div></td></tr></table>")
stringify = lambda x : "".join(x.xpath(".//text()"))
for x in tree.xpath("//table/tr"):
print "New row"
for y in x.xpath("td"):
print stringify(y)
Output:
New row
test
New row
test2
The following code will, however, get the list you ask for:
print map(stringify, tree.xpath("//table/tr/td"))
Output:
['test', 'test2']
This will find all text elements which are at all descended from a td which is a direct descendant of a tr which is in turn a direct descendant of a table.
(Simply asking for all text() elements will create some funny bugs when run on HTML which contains "<td>Foo <b>bar</b></td>" or similar.)
As I am well aware that PHPDom can solve half of my problem, I'm in need of a way (not necessarily regex) to be able to find a certain DOM element based on a given innerHTML.
say for example i got this code:
<tr>
<td class="ranking_rank" style="vertical-align:middle;">48697</td>
<td class="ranking_ign" style="vertical-align:middle;">kanineh</td>
<td class="ranking_img" style="vertical-align:middle;">
<img src="http://avatar.maplesea.com/Character/NKGEHGDLFNINKPMFLDCNNOHKHKBOHBKLGCBLABFLABHAGBPAEMDEFABJBLKJIHJAANGEKFJGELEPKMCNLKPCINEJDGAJFLKG.gif" onerror="this.src='/images/ranking/noimage.jpg'"/>
</td>
<td class="ranking_lvl" style="vertical-align:middle;">122</td>
<td class="ranking_world" style="vertical-align:middle;">
<img src="/images/ranking/Bootes.gif" onMouseover="ddrivetip('Bootes','white', 70)" onMouseout="hidetip()">
</td>
<td class="ranking_job" style="vertical-align:middle;">
<img src="/images/ranking/Warrior.gif" onMouseover="ddrivetip('Warrior','white', 70)" onMouseout="hidetip()">
</td>
<td class="ranking_fame" style="vertical-align:middle;">449</td>
</tr>
<tr>
<td class="ranking_rank" style="vertical-align:middle;">48698</td>
<td class="ranking_ign" style="vertical-align:middle;">WannaLogic</td>
<td class="ranking_img" style="vertical-align:middle;">
<img src="http://avatar.maplesea.com/Character/DOMELFGEGCGDBFCOLADBDOJLHADCIBNKEGKGINPNBEKPDDKOEEGBLMDLBGBDHGCNPGLAECAMLGKEMDKJGPODIDKCOJCMNNKN.gif" onerror="this.src='/images/ranking/noimage.jpg'"/>
</td>
<td class="ranking_lvl" style="vertical-align:middle;">122</td>
<td class="ranking_world" style="vertical-align:middle;">
<img src="/images/ranking/Aquila.gif" onMouseover="ddrivetip('Aquila','white', 70)" onMouseout="hidetip()">
</td>
<td class="ranking_job" style="vertical-align:middle;">
<img src="/images/ranking/Magician.gif" onMouseover="ddrivetip('Magician','white', 70)" onMouseout="hidetip()">
</td>
<td class="ranking_fame" style="vertical-align:middle;">56</td>
</tr>
I need to be able to get a hold of the whole row node with the td that has WannaLogic in it. that way, when I have this table row already, I can now easily traverse the nodes using PHP DOM. I'm a sucker for regular expression so I'd really much appreciate it if you can shed me some light on this.
Using regex on a DOM tree is a no-no and bound to fail when faced with malformed XML/HTML. Try this:
$xpath = new DOMXPath($doc);
$query = "//*[.='WannaLogic']";
$entries = $xpath->query($query);
foreach ($entries as $entry) {
// do whatever
}