通过带有嵌入式传单 svg 等的 RSelenium 提取基础数据

Kim*_*Kim 5 r web-scraping leaflet reactjs rselenium

我想提取有关此链接中每个广告的信息。现在,我已经到了可以自动单击 的阶段See Ad Details,但是有很多底层数据并不容易整理成一个整洁的数据框。

library(RSelenium)
rs <- rsDriver()
remote <- rs$client
remote$navigate(
  paste0(
    "https://www.facebook.com/ads/library/?", 
    "active_status=all&ad_type=political_and_issue_ads&country=US&", 
    "impression_search_field=has_impressions_lifetime&", 
    "q=actblue&view_all_page_id=38471053686"
  )
)

test <- remote$findElement(using = "xpath", "//*[@class=\"_7kfh\"]")
test$clickElement()
## Manually figured out element
test <- remote$findElement(using = "xpath", "//*[@class=\"_7lq0\"]")
test$getElementText()
Run Code Online (Sandbox Code Playgroud)

输出文本本身很乱,但我相信通过一些时间和努力,它可以被整理成有用的东西。问题是在处理底层数据

  1. 图表,这似乎只是一个图像,和
  2. Leaflet svg,当光标悬停在数据上时显示数据。

我不知道如何系统地提取此图像,尤其是传单 svg。在这种情况下,我将如何获取每个广告,然后提取详细信息中可用的完整数据?

Ser*_*ers 4

年龄和性别图形是画布元素。要将它们作为图像获取,您可以截取元素的屏幕截图。Python 示例:

driver.find_element_by_tag_name('canvas').screenshot("age_and_gender.png")
Run Code Online (Sandbox Code Playgroud)

该广告的显示位置是 SVG,您可以用相同的方式将其另存为图像。结果不会很准确,因为 SVG 的可见部分和实际是不同的。但您可以在之后裁剪图像。Python 示例:

driver.find_element_by_tag_name('svg').screenshot("where_this_ad_was_shown.png")
Run Code Online (Sandbox Code Playgroud)

要从中提取完整数据,您不能使用 Selenium。获取数据的方式是配置代理服务器,捕获 API 请求,并获取 JSON 格式的数据。是的,这是可能的。


简单的方法是使用一些请求来获取 AD 和详细信息,而无需使用 Selenium。Python 工作示例:

import json
import requests

params = (
    ('q', 'actblue'),
    ('count', '1000'), # default is 30, for 38471053686 it will return about 300 results.
    ('active_status', 'all'),
    ('ad_type', 'political_and_issue_ads'),
    ('countries/[0/]', 'US'),
    ('impression_search_field', 'has_impressions_lifetime'),
    ('view_all_page_id', '38471053686'),
)

data = {'__a': '1', }

with requests.session() as s:
    response = s.post('https://www.facebook.com/ads/library/async/search_ads/', params=params, data=data)
    ads = json.loads(response.text.replace('for (;;);', ''))['payload']['results']
    for ad in ads:
        ad_details_params = (
            ('ad_archive_id', ad[0]['adArchiveID']),
            ('country', 'US'),
        )
        response = s.post('https://www.facebook.com/ads/library/async/insights/', params=ad_details_params, data=data)
        print('parse json from response')
Run Code Online (Sandbox Code Playgroud)

不:未经书面许可,Facebook 不允许自动收集数据https://www.facebook.com/apps/site_scraping_tos_terms.php

但众所周知,Facebook 并不拒绝收集我们的数据。

每个 AD 详细信息的响应如下:

driver.find_element_by_tag_name('canvas').screenshot("age_and_gender.png")
Run Code Online (Sandbox Code Playgroud)

最后,要从 R 运行此 python 代码,请使用reticulate,然后将整个 python 脚本作为字符串运行 - 请注意,如果 python 脚本不包含任何"字符,则可以非常方便地直接放入 R 中,如下所示

library(reticulate)
py_run_string("import json
import requests
rest of script etc 
etc 
etc")
Run Code Online (Sandbox Code Playgroud)

此外,您还需要安装脚本使用的两个 python 库。这可以通过在 mac 上打开终端并输入pip install json安装jsonpython 库和pip install requestsrequests 库来完成)

  • 当我尝试(使用 R)时,我得到一个空的正文响应?请求网址中的 session_id 是否是问题所在(我已准确复制了答案中的 session_id) (2认同)
  • 其次@stevec,请求头中唯一改变的是sessionid。会话似乎更多的是单个页面视图。我尝试在服务器之前的响应中找到会话 ID,但没有成功。也许爵士可以分享一个可重现的例子? (2认同)