4
votes

XPath pour td / th basé sur le nombre de tr

Utilisation de XPath pour Webscrape.

La structure est:

      $route = $path->query("//tr[count(*) >= 2]/th");
      foreach ($route as $th){
          $property[] = trim($th->nodeValue);
      }

      $route = $path->query("//tr[count(*) >= 2]/td");
      foreach ($route as $td){
          $value[] = trim($td->nodeValue);
      }

mais l'un de ces tr contient juste un ième ou un td.

 $route = $path->query("//table[count(tr) > 1]//tr/td");

Donc je veux juste gratter si TR contient deux balises à l'intérieur. Je donne le chemin

 $route = $path->query("//table[count(tr) > 1]//tr/th");

ou

<table>
      <tbody>
         <tr>
            <th>

Mais cela ne fonctionne pas.

Je donne ici les liens de la table originale. Les deux derniers TR de la première table n'ont qu'un seul TD. Cela pose le problème. Et la deuxième ou la troisième table a également le même problème.

https://www.daiwahouse.co.jp/mansion/kanto/tokyo/y35/gaiyo.html

<table>
  <tbody>
     <tr>
        <th>
        <td>

J'essaye de sélectionnez TH et TD en même temps. MAIS si TR contient un TD, cela résout le problème. Parce que dans le nombre de TD et de TH ne sont pas les mêmes, je gratte plus de TD que de TH


4 commentaires

Vos XPath ne prennent pas en compte tbody .


Voulez-vous la ligne entière ou juste le premier th / td de la ligne?


Je pense que vous devez inspecter si le TR est juste un seul TD avec COLSPAN = "2" . Souhaitez-vous l'inclure ou l'exclure du scrape?


J'ai mis à jour la question à nouveau, veuillez la vérifier. @Scuzzy


3 Réponses :


2
votes

Ce XPath,

//tr[count(th) = count(td)]/*

sélectionnera tous les e éléments dans tous les éléments de table qui ont plus d'un tr descendant (que tbody soit présent ou non).


Ce XPath,

//tr[count(*) > 1]/*

sélectionnera tous les enfants des éléments tr avec plus d'un enfant.


Ce XPath,

//table[count(.//tr) > 1]/th

sélectionnera tous les enfants d'éléments tr où le nombre de e enfants est égal au nombre d'enfants td .


OP a publié un lien vers le site. L'élément racine se trouve dans l'espace de noms xmlns = "http://www.w3.org/1999/xhtml" .

Voir Comment XPath gère-t-il les espaces de noms XML?


10 commentaires

assez proche mais toujours en prenant des extras ... au final ma propriété (th) compte et ma valeur (th) compte ne sont pas les mêmes ...


Si vous pouviez indiquer précisément ce que vous essayez de sélectionner, il serait simple d'écrire le XPath. Par exemple, «J'essaie de sélectionner ____ éléments lorsque les conditions suivantes sont remplies: ______. Notez que je ne veux pas de ces éléments lorsque la condition ____ est remplie.» J'ai jeté une deuxième estimation de ce que vous pourriez vouloir entre-temps.


J'ai mis à jour la question et donné le lien du tableau d'origine. pourriez-vous s'il vous plaît vérifier.


Votre mise à jour n'a toujours pas dit quels éléments vous souhaitez sélectionner ( td , th , soit, tr , table , etc), et vous n'avez pas clairement spécifié les conditions permettant de distinguer quel élément vous voulez dont vous ne voulez pas.


J'essaye de sélectionner TH et TD en même temps. MAIS si TR contient un TD, cela résout le problème. Parce que dans le compte et le TD et le TH ne sont pas les mêmes, je racle plus de TD que le TH


Mis à jour avec XPath qui ne sélectionnera les éléments td et th que lorsqu'il y en a un nombre égal dans un tr . Est-ce que c'est ce que tu veux?


merci beaucoup cela a presque résolu le problème. l'opposé de ce // tr [count (th) = count (td)] / * est ceci; // tr [count (td) = count (th)] / * car j'ai deux requêtes dont l'une est la valeur de TH et l'autre est TD comme dans la mise à jour de la question ...


Quoi? count (th) = count (td) équivaut à, et non "l'opposé de" count (td) = count (th) . Désolé, mais c'est une quantité excessive de va-et-vient. J'avance. Bonne chance.


Très bien, je suis content que vous ayez résolu le problème. Je ne sais pas comment j'ai aidé, mais j'espère l'avoir fait. :-)


Haha, tu l'as vraiment fait! :)



0
votes

Si je comprends bien, vous voulez des e éléments dans les tr s qui contiennent deux éléments? Je pense que c'est ce dont vous avez besoin:

//th[count(../*) = 2]


3 commentaires

ok, je l'ai essayé comme ceci //th[count(../*) == 2] mais, cette erreur apparaît. "Argument non valide fourni pour foreach ()" à quoi sert "*"?


Pour expliquer par exemple, count (tr) compte le nombre d'éléments tr (pas le nombre d'éléments sous un tr ). count (*) compte chaque nœud dans le chemin actuel. count (../*) compte le nombre de frères et sœurs du nœud actuel.


J'ai mis à jour la question et donné le lien du tableau d'origine. pourriez-vous s'il vous plaît vérifier.



0
votes

J'ai inclus un chemin plus explicite dans ma réponse avec une instruction ou pour compter les éléments TH et TD

//table[ count( descendant::td | descendant::th ) > 1]//tr

Vous pouvez également l'utiliser pour n'importe quelle profondeur descendants

$html = '
  <html>
    <body>
      <table>
        <tbody>
          <tr>
            <th>I am Included</th>
            <td>I am a column</td>
          </tr>
        </tbody>
      </table>
      <table>
        <tbody>
          <tr>
            <th>I am ignored</th>
          </tr>
        </tbody>
      </table>
      <table>
        <tbody>
          <tr>
            <th>I am also Included</th>
            <td>I am a column</td>
          </tr>
        </tbody>
      </table>
    </body>
  </html>
';

$doc = new DOMDocument();
$doc->loadHTML( $html );

$xpath = new DOMXPath( $doc );
$result = $xpath->query("//table[ count( tbody/tr/td | tbody/tr/th ) > 1 ]/tbody/tr");

foreach( $result as $node )
{
  var_dump( $doc->saveHTML( $node ) );
}

// string(88) "<tr><th>I am Included</th><td>I am a column</td></tr>"
// string(93) "<tr><th>I am also Included</th><td>I am a column</td></tr>"

Changez le xpath après la condition (partie entre crochets) pour changer ce que vous retournez.


1 commentaires

J'ai mis à jour la question et donné le lien du tableau d'origine. pourriez-vous s'il vous plaît vérifier.