найти элементы по xpath selenium phantomjs - PullRequest
0 голосов
/ 23 ноября 2018

Я использую Rselenium для утилизации.Для этого я установил java и JDK's, chromedriver, selenium server standalone и браузер без головы phantomjs в своей виртуальной машине Google Cloud.

Мне нужно перехватить текстпервый рейтинг:

remDr <- remoteDriver(browserName = 'chrome', port = 4444L)
remDr$open()
remDr$setWindowSize(1280L, 1024L)
remDr$navigate("https://www.ratebeer.com/reviews/sullerica-1561/294423")
text_post = remDr$findElements("xpath",'//*[@id="root"]/div/div[2]/div/div[2]/div[2]/div/div[1]/div[3]/div/div[2]/div[1]/div/div[2]/div/div[1]/div/div/div[1]')

text_post
## list()

Наконец text_post пусто.

Однако, если я протестирую тот же сценарий на своем локальном ноутбуке с RSelenium, браузером Chrome и тем же XPath, это будет успех!

Что происходит?

Это из-за использования фантомов?

Заранее спасибо.

sessionInfo()

R version 3.4.4 (2018-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.5 LTS

Ответы [ 2 ]

0 голосов
/ 23 ноября 2018

Вам не нужна тяжелая сторонняя зависимость.Этот сайт использует graphql POST запросы изнутри в асинхронных XHR-запросах для извлечения данных.Вы можете увидеть это, если откроете Инструменты разработчика и enter image description here

Я сделал «Копировать POST-данные» (обычно один и тот же или похожий пункт контекстного меню во всех браузерах) исвернул запрос graphql на вкладке Response, чтобы показать вам, что это такое, а также, возможно, упростить вам просмотр запроса и дополнить его самостоятельно (то, что я только что сказал, выходит за рамки ", но как насчет… »Следуйте на вопросы в комментариях; пожалуйста, напишите новый вопрос, если вам нужна помощь в этом.)

'[
    {
        "operationName": "beer",
        "query": "query beer($beerId: ID!) {\n  info: beer(id: $beerId) {\n    id\n    name\n    __typename\n  }\n}\n",
        "variables": {
            "beerId": "294423"
        }
    },
    {
        "operationName": "beer",
        "query": "query beer($beerId: ID!) {\n  info: beer(id: $beerId) {\n    id\n    name\n    styleScore\n    overallScore\n    averageRating\n    ratingCount\n    __typename\n  }\n}\n",
        "variables": {
            "beerId": "294423"
        }
    },
    {
        "operationName": "beerReviews",
        "query": "query beerReviews($beerId: ID!, $authorId: ID, $order: ReviewOrder, $after: ID) {\n  beerReviewsArr: beerReviews(beerId: $beerId, authorId: $authorId, order: $order, after: $after) {\n    items {\n      ...ReviewItem\n      __typename\n    }\n    totalCount\n    last\n    __typename\n  }\n}\n\nfragment ReviewItem on Review {\n  id\n  comment\n  score\n  scores {\n    appearance\n    aroma\n    flavor\n    mouthfeel\n    overall\n    __typename\n  }\n  author {\n    id\n    username\n    reviewCount\n    __typename\n  }\n  checkin {\n    id\n    place {\n      id\n      name\n      city\n      state {\n        id\n        name\n        __typename\n      }\n      country {\n        id\n        name\n        __typename\n      }\n      __typename\n    }\n    __typename\n  }\n  servedIn\n  likeCount\n  likedByMe\n  createdAt\n  updatedAt\n  __typename\n}\n",
        "variables": {
            "beerId": "294423",
            "first": 7,
            "order": "RECENT"
        }
    }
]' -> graphql_query

Нам нужно будет сократить это обратно в одну строку для вызова API (что я делаю сgsub() ниже. Нам также нужно вручную указать тип содержимого и убедиться, что httr не пытается манипулировать данными тела, установив кодировку на raw:

httr::POST(
  url = "https://beta.ratebeer.com/v1/api/graphql/",
  httr::content_type("application/json"),
  encode = "raw",
  body = gsub("\n", " ", graphql_query),
  httr::verbose()
) -> res

Теперь у нас есть структурированная, но в значительной степени вложенный, список с вашим ifo в нем. Уверен, что вы после items ниже:

str(httr::content(res), 4)
## List of 3
##  $ :List of 1
##   ..$ data:List of 1
##   .. ..$ info:List of 3
##   .. .. ..$ id        : chr "294423"
##   .. .. ..$ name      : chr "Sullerica 1561"
##   .. .. ..$ __typename: chr "Beer"
##  $ :List of 1
##   ..$ data:List of 1
##   .. ..$ info:List of 7
##   .. .. ..$ id           : chr "294423"
##   .. .. ..$ name         : chr "Sullerica 1561"
##   .. .. ..$ styleScore   : num 35.1
##   .. .. ..$ overallScore : num 51.8
##   .. .. ..$ averageRating: num 3.25
##   .. .. ..$ ratingCount  : int 21
##   .. .. ..$ __typename   : chr "Beer"
##  $ :List of 1
##   ..$ data:List of 1
##   .. ..$ beerReviewsArr:List of 4
##   .. .. ..$ items     :List of 10
##   .. .. ..$ totalCount: int 21
##   .. .. ..$ last      : chr "7177326"
##   .. .. ..$ __typename: chr "ReviewList"

У него есть только 10 из 21, поэтому прокрутите вниз в окне браузера с помощью инструментов разработчикаоткрой и посмотриво втором POST запросе, который был сделан, посмотрите, какие параметры изменились, и теперь у вас будет еще лучшее представление о том, как получить доступ к внутреннему API-интерфейсу сайта, по сравнению с поиском контента.

0 голосов
/ 23 ноября 2018

В соответствии с HTML, вы можете использовать xpath как:

//div[@id="root"]//span[contains(.,'20')]//following::div[contains(@class,'LinesEllipsis')]

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

...