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 при его оценке?

Результатом $x является массив, поэтому вы также можете использовать функции массива, такие как map, например. $x('//*[@id = "mount_0_0_OV"]/div/div[1]/div/div[3]/div/div/di‌​v/div[1]/div[1]/div/‌​div/div[4]/div/div/d‌​iv/div/div/div/div/d‌​iv/div[3]/div[2]/div‌​[2]/div[1]/a').map(l‌​ink => link.href) для дальнейшей обработки. (Обратите внимание, что используемый XPath немного отличается от вашего, поскольку вы ничего не выбрали для меня, поэтому я позволил браузеру предложить мне тот, который используется в моем примере).

Martin Honnen 01.04.2023 12:12

@MartinHonnen Я не уверен, что следую за тобой. Что должно делать ваше выражение?

d-b 01.04.2023 13:00

«Обратите внимание, что используемый XPath немного отличается от вашего, поскольку вы ничего не выбрали для меня» - да, это моя проблема и причина, по которой я задал этот вопрос. Когда я выполняю ваше выражение в консоли Safari, я получаю [] (0) = $10-, что тоже немного пусто. Вы получаете другой результат, чем я? Спасибо.

d-b 01.04.2023 13:02

Я понял из вашего описания, что для вашего, например. $x('//*[@id = "mount_0_0_MW"]/div/div[1]/div/div[3]/div/div/di‌​v/div[1]/div[1]/div/‌​div/div[4]/div/div/d‌​iv/div/div/div/div/d‌​iv/div[3]/div/div[2]‌​/div[1]/a') выбрал нужные a элементы в вашем браузере, но каким-то образом попытка использовать путь $x('//*[@id = "mount_0_0_MW"]/div/div[1]/div/div[3]/div/div/di‌​v/div[1]/div[1]/div/‌​div/div[4]/div/div/d‌​iv/div/div/div/div/d‌​iv/div[3]/div/div[2]‌​/div[1]/a'/@href) каким-то образом с API/движком XPath вашего браузера не удалась.

Martin Honnen 01.04.2023 16:38

Поэтому я предложил альтернативу для получения значения атрибута/свойства href, а именно $x('//*[@id = "mount_0_0_MW"]/div/div[1]/div/div[3]/div/div/di‌​v/div[1]/div[1]/div/‌​div/div[4]/div/div/d‌​iv/div/div/div/div/d‌​iv/div[3]/div/div[2]‌​/div[1]/a').map(link => link.href). Только для тестирования в Chrome в Windows мне нужно было использовать другое выражение пути, а именно //*[@id = "mount_0_0_OV"]/div/div[1]/div/div[3]/div/div/div/di‌​v[1]/div[1]/div/div/‌​div[4]/div/div/div/d‌​iv/div/div/div/div/d‌​iv[3]/div[2]/div[2]/‌​div[1]/a.

Martin Honnen 01.04.2023 16:41

@MartinHonnen Xpath, оканчивающийся на @href, терпит неудачу в том отношении, что он не возвращает атрибут @href, а просто возвращает пустую строку (или массив пустых строк).

d-b 01.04.2023 18:16

@MartinHonnen Ваш пример, оканчивающийся на .map(link => link.href), сработал. Спасибо. Как вы думаете, вы можете объяснить, почему / как это работает? Если вы опубликуете это как ответ, я приму это решение.

d-b 01.04.2023 18:18
Почему Facebook остановился на PHP
Почему Facebook остановился на PHP
PHP имеет долгую историю с Facebook, и это был основной язык программирования, использовавшийся для создания сайта в первые годы его существования....
0
7
86
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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, ориентированный на семантику вашего поиска, вероятно, будет более надежным и устойчивым перед лицом изменений.

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

d-b 01.04.2023 15:32

Я выполнил свое первое предложение в инструментах разработчика Chrome, используя функцию $x, и получил список элементов a.

Conal Tuohy 01.04.2023 15:37

Мне было непонятно, какое клиентское приложение вы пишете; может быть, Selenium, может быть, пользовательский скрипт браузера (JS)? Поэтому я просто написал XPath для извлечения элементов a. Может быть, вам нужно показать остальную часть вашего кода?

Conal Tuohy 01.04.2023 15:41

Я отредактировал свой ответ, чтобы показать результаты, которые я получил

Conal Tuohy 01.04.2023 16:04

Когда я выполняю ваше предложение, вот результат: imgur.com/a/tZ9HO7y

d-b 01.04.2023 18:21

Я пишу AppleScript для управления Safari, используя do javascript-метод Safari.

d-b 01.04.2023 18:22

Это странно, когда я пытаюсь $x('//a[starts-with(@href, "https://www.facebook.com/profile.php?")]/@href') иногда получается результат, а иногда нет. Firefox работал imgur.com/a/vjOmPnw, но Chrome и Safari возвращают пустые результаты.

d-b 01.04.2023 21:37
Ответ принят как подходящий

Основываясь на вашем описании (и без доступа к 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.

Вы никогда не сможете быть счастливы ... Я пытаюсь использовать это с document.evaluate, но, как бы я ни использовал суффикс, который вы предлагаете, .map(link => link.href) я не могу заставить его работать. «Корневой» xpath работает нормально, но как только я добавляю .map(link => link.href), я получаю различные сообщения об ошибках, в основном «TypeError Map не является функцией». Есть идеи, как использовать .map(link => link.href) с document.evaluate? Спасибо.

d-b 02.04.2023 00:23

Метод map работает с массивами или объектами, подобными массивам; document.evaluate ничего подобного не возвращает.

Martin Honnen 02.04.2023 01:12

Другие вопросы по теме