XPath 使用总结

php  

郑重声明: 以下代码仅适用学习,未经本人同意禁止转发!

最近有需求需要对HTML页面DOM进行数据抓取,好久不用,几乎不会了.这里记录总结一下

  • 首先本人使用PHP实现的,这里贴一下代码,然后屡一下思路

    • PHP代码

      1. # 定义需要抓取的数据
      2. $data = [
      3. 'name' => '', // 姓名
      4. 'age' => '', // 出生时间
      5. 'age_num' => '', // 年龄
      6. 'work_year' => '', // 参加工作时间
      7. 'work_num' => '', // 工作年限
      8. 'education' => '', // 学历
      9. 'graduate' => '', // 毕业院校
      10. 'major' => '', // 专业
      11. 'work_place' => '', // 最近工作单位
      12. ];
      13. $dom = new \DOMDocument();
      14. # 将字符串加载HTML,这里增加UTF8字符集,解决乱码
      15. @$dom->loadHTML('<?xml encoding="UTF-8">' . $html_text);
      16. # 将该HTML规范化
      17. $dom->normalize();
      18. # 用DOMXpath加载DOM,用于查询
      19. $xpath = new \DOMXPath($dom);
      20. # 获取名称
      21. $found_name = @$xpath->query('//div[@class="resume-item item-base"]//div[@class="geek-name"]')->item(0)->nodeValue;
      22. !empty($found_name) && $data['name'] = $found_name;
      23. # 获取年龄
      24. $found_age = @$xpath->query('//div[@class="resume-item item-base"]//i[@class="fz fz-age"]')->item(0)->parentNode->nodeValue;
      25. if (!empty($found_age)) {
      26. $found_age = preg_split("/([0-9]+)/", $found_age, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)[0];
      27. $data['age_num'] = $found_age;
      28. $data['age'] = date('Y-01-01 H:i:s', strtotime('-' . $found_age . ' year'));
      29. }
      30. # 获取工作年限
      31. $founnd_work_num = @$xpath->query('//div[@class="resume-item item-base"]//i[@class="fz fz-experience"]')->item(0)->parentNode->nodeValue;
      32. if (!empty($founnd_work_num)) {
      33. # 将数字与汉字切割分离
      34. $founnd_work_num = preg_split("/([0-9]+)/", $founnd_work_num, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)[0];
      35. $data['work_num'] = $founnd_work_num;
      36. $data['work_year'] = date('Y-01-01 H:i:s', strtotime('-' . $founnd_work_num . ' year'));
      37. }
      38. # 获取学历,毕业院校,专业,工作单位
      39. $items = @$xpath->query('//div[@class="resume-item"]');
      40. if (!empty($items)) {
      41. foreach ($items as $item) {
      42. $pro_name = @$item->getElementsByTagName('h3')->item(0)->nodeValue;
      43. if (!empty($pro_name) && $pro_name == '教育经历') {
      44. $all_value = @$item->getElementsByTagName('h4')->item(0)->nodeValue;
      45. if (!empty($all_value)) {
      46. $all_value = str_replace(' ', '', $all_value);
      47. $all_value = str_replace(' ', '', $all_value);
      48. $all_value_arr = array_values(array_filter(explode(PHP_EOL, trim($all_value))));
      49. if (!empty($all_value_arr[0])) {
      50. $data['graduate'] = $all_value_arr[0];
      51. }
      52. if (!empty($all_value_arr[1])) {
      53. $data['major'] = $all_value_arr[1];
      54. }
      55. if (!empty($all_value_arr[0] && !empty($all_value_arr[1] && !empty($all_value_arr[2])))) {
      56. $data['education'] = $all_value_arr[2];
      57. }
      58. }
      59. } elseif (!empty($pro_name) && $pro_name == '工作经历') {
      60. $all_value = @$item->getElementsByTagName('h4')->item(0)->nodeValue;
      61. $all_value = str_replace(' ', '', $all_value);
      62. $all_value = str_replace(' ', '', $all_value);
      63. $all_value_arr = array_values(array_filter(explode(PHP_EOL, trim($all_value))));
      64. if (!empty($all_value_arr[0])) {
      65. $data['work_place'] = $all_value_arr[0];
      66. }
      67. }
      68. }
      69. }
  • 然后查了一下XPath的使用手册

    • 这个需要理解,使用路劲表达式进行节点选取

常用表达式解释

表达式 描述
nodename(xxxx) 选取此节点的所有子节点
/ 从根节点选取
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

常用表达式例子

路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。

谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点
谓语被嵌在方括号中

谓语例子

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

选取未知节点
XPath 通配符可用来选取未知的 XML 元素

通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

未知节点通配符例子

路径表达式 结果
/bookstore/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性的 title 元素。

选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。
若干路劲例子

路径表达式 结果
//book/title //book/price 选取 book 元素的所有 title 和 price 元素。
//title //price 选取文档中的所有 title 和 price 元素。
/bookstore/book/title //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

总结

还有很多实用方法, W3school手册
选取节点找大的唯一标识属性查找下面的小唯一标识属性
如果情况不多只有一种就直接定位过去拿值
如果会出现不确定的情况,就定位下面的节点,找到不一样的地方进行判断,当定位到了以后可以使用getElementsByTagName 等方法查出指定标签的所有的值再进行获取



评论 0

发表评论

Top