通过 xpath selenium phantomjs 查找元素
find elements by xpath selenium phantomjs
我正在使用 Rselenium
进行报废。为此,我在 Google Cloud 的 VM 实例中安装了 java
和 JDK's
、chromedriver
、selenium server standalone
和无头浏览器 phantomjs
。
我需要抓取第一评分的文字:
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 测试相同的脚本,它就成功了!
这是怎么回事?
是不是使用了phantomjs?
提前致谢。
sessionInfo()
R version 3.4.4 (2018-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.5 LTS
根据 HTML,您可以使用 xpath 作为:
//div[@id="root"]//span[contains(.,'20')]//following::div[contains(@class,'LinesEllipsis')]
注意:由于元素是动态生成的元素,因此您必须引入 WebDriverWait 才能使 元素可见.
您不需要重量级的第三方依赖项。该站点在异步 XHR 请求中使用 graphql POST
请求来检索数据。打开开发者工具就可以看到
我做了一个 "Copy POST Data"(在所有浏览器中通常是相同或非常相似的上下文菜单项)并取消最小化响应选项卡中的 graphql 查询只是为了向您展示它是什么,也许,让您更轻松地查看查询并自行扩充它(我刚才所说的超出了 "but what about…" 的范围,请继续评论中的问题;如果您需要帮助,请提出一个新问题)。
'[
{
"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"
它确实只有 21 个中的 10 个,所以在浏览器中向下滚动 window,打开开发者工具,查看发出的第二个 POST
请求,查看更改了哪些参数,现在您将更好地了解如何访问网站的后端 API 而不是必须抓取内容。
我正在使用 Rselenium
进行报废。为此,我在 Google Cloud 的 VM 实例中安装了 java
和 JDK's
、chromedriver
、selenium server standalone
和无头浏览器 phantomjs
。
我需要抓取第一评分的文字:
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 测试相同的脚本,它就成功了!
这是怎么回事?
是不是使用了phantomjs?
提前致谢。
sessionInfo()
R version 3.4.4 (2018-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.5 LTS
根据 HTML,您可以使用 xpath 作为:
//div[@id="root"]//span[contains(.,'20')]//following::div[contains(@class,'LinesEllipsis')]
注意:由于元素是动态生成的元素,因此您必须引入 WebDriverWait 才能使 元素可见.
您不需要重量级的第三方依赖项。该站点在异步 XHR 请求中使用 graphql POST
请求来检索数据。打开开发者工具就可以看到
我做了一个 "Copy POST Data"(在所有浏览器中通常是相同或非常相似的上下文菜单项)并取消最小化响应选项卡中的 graphql 查询只是为了向您展示它是什么,也许,让您更轻松地查看查询并自行扩充它(我刚才所说的超出了 "but what about…" 的范围,请继续评论中的问题;如果您需要帮助,请提出一个新问题)。
'[
{
"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"
它确实只有 21 个中的 10 个,所以在浏览器中向下滚动 window,打开开发者工具,查看发出的第二个 POST
请求,查看更改了哪些参数,现在您将更好地了解如何访问网站的后端 API 而不是必须抓取内容。