Xpath - получить значение атрибута?

Я прочитал этот вопрос и этот вопрос, и, возможно, больше вопросов, и хочу сделать именно то, что они там делают, но я просто получаю пустые результаты, когда пытаюсь.

Я хочу извлечь ссылку на профиль для всех подписчиков здесь https://www.facebook.com/zuck/followers

Очень грубый Xpath, указывающий на имя подписчика, которое является кликабельной ссылкой: //*[@id = "mount_0_0_MW"]/div/div[1]/div/div[3]/div/div/div/div[1]/div[1]/div/div/div[4]/div/div/div/div/div/div/div/div/div[3]/div/div[2]/div[1]/a

Тег a, на который я указываю, обычно выглядит примерно так:

<a class = "x1i10hfl xjbqb8w x6umtig x1b1mbwd xaqea5y xav7gou x9f619 x1ypdohk xt0psk2 xe8uvvx xdj266r x11i5rnm xat24cr x1mh8g0r xexx8yu x4uap5 x18d9i69 xkhd6sd x16tdsg8 x1hl2dhg xggy1nq x1a2a7pz x1heor9g xt0b8zv" href="https://www.facebook.com/profile.php?id=100072622654958" role = "link" tabindex = "0">

Чтобы извлечь значение href, я, согласно связанному вопросу, добавляю /@href в конец xpath выше, но когда я оцениваю это выражение, используя $x в консоли браузера (в Safari), я получаю пустой результат:

Как мне переписать свой xpath, чтобы получить массив со значениями в атрибуте href при его оценке?


86
2

Ответы:

Попробуйте XPath следующим образом:

//a[starts-with(@href, "https://www.facebook.com/profile.php?")]/@href

В инструментах разработчика Chrome:

$x('//a[starts-with(@href, "https://www.facebook.com/profile.php?")]/@href')

Результат:

Array(24) [ 
href = "https://www.facebook.com/profile.php?id=100025227933647", 
href = "https://www.facebook.com/profile.php?id=100025227933647", 
href = "https://www.facebook.com/profile.php?id=100004202773657", 
href = "https://www.facebook.com/profile.php?id=100004202773657", 
href = "https://www.facebook.com/profile.php?id=100089136296666", 
href = "https://www.facebook.com/profile.php?id=100089136296666", 
href = "https://www.facebook.com/profile.php?id=100088772316924", 
href = "https://www.facebook.com/profile.php?id=100088772316924", 
href = "https://www.facebook.com/profile.php?id=100090228025189", 
href = "https://www.facebook.com/profile.php?id=100090228025189", 
… ]

... или, может быть, если вы хотите начать с ограничения поиска в определенной части страницы, как в приведенном выше примере XPath:

//*[@id = "mount_0_0_MW"]//a[starts-with(@href, "https://www.facebook.com/profile.php?")]/@href

Это поиск a элементов, ссылки на которые ведут на страницы профиля Facebook.

Я видел много вопросов на этом сайте, когда у людей возникают проблемы с XPath, предложенным их браузером, и их выражение выглядит примерно так:

/div[2]/div[2]/div[1]/div[3]/div[1]/a

Выражения XPath, подобные этим, легко генерируются браузером, так как они просто восходят от выбранного элемента вверх по иерархии элементов, считая предшествующих братьев и сестер на каждом уровне. Но обычно они не очень надежны, потому что они зависят от HTML-страницы, имеющей фиксированную структуру, которая не меняется. Если бы страница добавила дополнительный элемент div в какой-то ключевой части страницы, то XPath мог бы легко в конечном итоге указать куда-то не туда, куда он указывал раньше.

По моему мнению, людям часто лучше самим написать XPath, который выражает то, что они на самом деле ищут. В вашем случае вы на самом деле не ищете элементы a, которые появляются на определенном уровне в иерархии div; вы на самом деле ищете ссылки на профили. XPath, ориентированный на семантику вашего поиска, вероятно, будет более надежным и устойчивым перед лицом изменений.


Решено

Основываясь на вашем описании (и без доступа к Mac/Safari для тестирования), похоже, что оценка XPath для узла атрибута каким-то образом терпит неудачу, в качестве альтернативы я думаю, что вы можете полагаться на XPath только для выбора элементов @href. , затем используйте методы массива JavaScript, такие как a (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) и обычные свойства DOM браузера, такие как map; это означало бы, что вы используете, например.

$x('//*[@id = "mount_0_0_MW"]/div/div[1]/div/div[3]/div/div/div/div[1]/div[1]/div/div/div[4]/div/div/div/div/div/div/div/div/div[3]/div/div[2]/div[1]/a').map(link => link.href)

где вызов .href возвращает массив узлов элементов $x(..), а последующий вызов a отображает этот массив узлов элементов map в массив строковых значений на основе свойства a элементов href.