当前位置: 首页 > 面试题库 >

获取具有随机类名的元素

伏欣悦
2023-03-14
问题内容

看起来Instagram网站上的<class id>for<img class>每天都在变化。现在是FFVAD,明天将是另一回事。例如(我把它缩短了,链接很长):

<img class="FFVAD" alt="Tag your best friend" decoding="auto" style="" sizes="293px" src="https://scontent- lax3-2.cdninstagram.com/vp/0436c00a3ac9428b2b8c977b45abd022/5BAB3EBC/t51.2885-15/s640x640/sh0.08/e35/33110483_592294374461447_8669459880035221504_n.jpg">

话虽如此,我需要修复脚本并对其进行硬编码Class ID,以便能够抓取该网页。

var = driver.find_elements_by_class_name('FFVAD')

有人告诉我,我可以img.get_attribute('class')用来查找class ID并将其存储以备后用。但是我仍然不知道如何实现这一目标,因此硒或汤可以Class ID从中获取html tag并在以后存储或解析。

我现在所得到的就是这个。它有点脏,不是正确的,但是想法就在那里。

import requests
import selenium.webdriver as webdriver

url = ('https://www.instagram.com/kitties')
driver = webdriver.Firefox()
driver.get(url)
last_height = driver.execute_script("return document.body.scrollHeight")

while True:
    imgs_dedupe = driver.find_elements_by_class_name('FFVAD')

    for img in imgs_dedupe:
        posts = img.get_attribute('class')
        print posts

    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(scroll_delay)
    new_height = driver.execute_script("return document.body.scrollHeight")

    if new_height == last_height:
        break
    last_height = new_height

运行它时,我得到此输出,并且由于页面上有3张图像,所以得到3倍 Class ID

python tag_print.py 
FFVAD
FFVAD
FFVAD

问题答案:

您当前正在通过硬编码的类名称搜索该元素。

如果类名是随机的,则不能再对其进行硬编码。您必须:

  • 通过其他特征 (例如,元素层次结构,某些其他属性等) 搜索元素 ; XPath可以做到这一点

    In [10]: driver.find_elements_by_xpath('//article//img')
    

    Out[10]:
    [ ,
    ,
    ]


    • 您还 可以按元素的 视觉特征进行 搜索:大小,可见性,位置。但是,这不能仅通过XPath来完成,您必须获取所有<img>标记并用手检查每个标记。
      (因为很长,请参见下面的示例。)
  • 从其他页面逻辑中以某种方式学习该类名 (如果页面的逻辑本身可以找到和使用它,则它必须存在于其他地方,并且该逻辑必须由其他东西找到,等等)

在这种情况下,类名是renderImage函数中局部变量的一部分,因此只能通过探索AST来通过DOM进行挽救。该函数本身埋在webpack机器内部的某个位置(它似乎将所有资源打包到几个带有一个字母名称的全局对象中)。或者,您可以将所有包含的JS文件作为原始数据读取,并renderImage在其中查找定义。因此,在这种情况下,尽管理论上仍然可行,但是这是不成比例的。

通过视觉特征获取元素的示例

无论在任何页面上,都
可以找到并排放置的3张相同大小的图像(这是它们在https://www.instagram.com/kitties上的显示方式)。

由于HTMLElement不能直接将s传递给Python(至少,我找不到任何方法),因此我们需要传递一些唯一的ID来代替它们,例如唯一的XPath。

(JS代码可能更优雅,我对此语言没有太多经验)

In [22]: script = """
  //https://stackoverflow.com/questions/2661818/javascript-get-xpath-of-a-node/43688599#43688599
  function getXPathForElement(element) {
      const idx = (sib, name) => sib 
          ? idx(sib.previousElementSibling, name||sib.localName) + (sib.localName == name)
          : 1;
      const segs = elm => !elm || elm.nodeType !== 1 
          ? ['']
          : elm.id && document.querySelector(`#${elm.id}`) === elm
              ? [`id("${elm.id}")`]
              : [...segs(elm.parentNode), `${elm.localName.toLowerCase()}[${idx(elm)}]`];
      return segs(element).join('/');
  }

  //https://plainjs.com/javascript/styles/get-the-position-of-an-element-relative-to-the-document-24/
  function offsetTop(el){
    return window.pageYOffset + el.getBoundingClientRect().top;
  }

  var expected_images=3;
  var found_groups=new Map();
  for (e of document.getElementsByTagName('img')) {
    let group_id = e.offsetWidth + "x" + e.offsetHeight;
    if (!(found_groups.has(group_id))) found_groups.set(group_id,[]);
    found_groups.get(group_id).push(e);
  }
  for ([k,v] of found_groups) {
    if (v.length != expected_images) {found_groups.delete(k);continue;}
    var offset_top = offsetTop(v[0]);
    for (e of v){
      let _c_oft = offsetTop(e);
      if (_c_oft !== offset_top){
        found_groups.delete(k);
        break;
      }
    }
  }
  if (found_groups.size != 1) {
    console.log(found_groups);
    throw 'Unexpected pattern of images after filtering';
  }

  var found_group = found_groups.values().next().value;


  result=[]
  for (e of found_group) {
    result.push(getXPathForElement(e));
  }
  return result;
"""

In [23]: d.execute_script(script)
Out[23]:
[u'id("react-root")/section[1]/main[1]/div[1]/article[1]/div[1]/div[1]/div[1]/div[1]/a[1]/div[1]/div[1]/img[1]',
 u'id("react-root")/section[1]/main[1]/div[1]/article[1]/div[1]/div[1]/div[1]/div[2]/a[1]/div[1]/div[1]/img[1]',
 u'id("react-root")/section[1]/main[1]/div[1]/article[1]/div[1]/div[1]/div[1]/div[3]/a[1]/div[1]/div[1]/img[1]']

In [27]: [d.find_element_by_xpath(xp) for xp in _]
Out[27]:
[<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="1ab4eeb4-10c4-4da4-996c-ee6744445dcc", element="55c48964-8cd0-4472-b35b-214a5a9bfbf7")>,
 <selenium.webdriver.firefox.webelement.FirefoxWebElement (session="1ab4eeb4-10c4-4da4-996c-ee6744445dcc", element="b7f7c8a4-e343-49ca-b416-49f72e67ae07")>,
 <selenium.webdriver.firefox.webelement.FirefoxWebElement (session="1ab4eeb4-10c4-4da4-996c-ee6744445dcc", element="728f6148-6a03-4c9a-9933-36859d65eb51")>]


 类似资料:
  • 我是Jsoup解析的新手,我想获得这个页面上所有公司的列表:https://angel.co/companies?company_types[]=startup现在,一种实现这一点的方法实际上是使用与我需要的相关的div标记来检查页面。但是,当我调用该方法时: 首先,我甚至无法在我的consol html输出中找到那些DIV标记(这些标记应该给出公司的列表);其次,即使我找到了它,我如何才能找到具

  • 我试图创建一个并发的数据结构,它允许一个线程轮询随机元素,而另一个线程正在写入它。 我担心的是:在极端情况下,例如,在线程A调用(在中)之后,线程B删除最后一个元素。不幸的是,随机索引恰好是最后一个元素(已被删除)的索引。因此,调用将抛出未捕获的。这是我所不期望的-调用失败,即使此列表中仍有元素。 所以我想问:我的担心是真的吗?也许我误解了(或任何其他类型的并发列表)实际上是做什么的?如果我的担心

  • 借助新的 Firebase API,您可以通过客户端代码将文件上传到云存储中。这些示例假定文件名在上传过程中是已知的或静态的: 或 随着用户上传自己的文件,名称冲突将成为一个问题。如何让Firebase创建文件名而不是自己定义?数据库中是否有类似于<code>push()的<code>功能来创建唯一的存储引用?

  • 问题内容: 我正在使用PHPDOM,并且试图在DOM节点中获取具有给定类名的元素。获得该子元素的最佳方法是什么? 更新: 我最终使用了PHP,它更容易使用。 问题答案: 更新:CSS选择器的Xpath版本 因此,在下面我回应hakre的评论之后,我感到好奇,并调查了后面的代码。看起来上面的选择器已编译为以下xpath(未经测试): 所以PHP将是: 基本上,我们在这里所做的就是规范化属性,以便即使

  • 问题内容: 我想知道在特定范围内生成随机数的最佳方法(例如在Java中)是什么,而每个范围内的每个数字都有一定的发生概率? 例如 从[1; 3]内产生随机整数,并具有以下概率: P(1)= 0.2 P(2)= 0.3 P(3)= 0.5 现在,我正在考虑在[0; 100]内生成随机整数并执行以下操作的方法: 如果它在[0; 20]之内->我得到我的随机数1。 如果它在[21; 50]之内->我得到

  • 问题内容: 我有一个像这样的数组: 我想从该数组中获取3个随机元素。我来自C#,但是我不确定该从哪里开始。我想我应该先对数组进行随机排序,然后再从中选择前3个项目? 我尝试使用以下扩展名将其改组: 但随后在“ shuffle()”的位置说“’()’不可转换为’[Int]’”。 为了挑选一些元素,我使用: 到目前为止看起来还不错。 如何洗牌?还是有人对此有更好/更优雅的解决方案? 问题答案: Xco