冰箱研会长e-3M 发表于 2021-8-30 16:14

怎么用JS脚本获取链接内的元素?

如图, 这是一张qq相册网页的截图
https://gitee.com/Arxher/cra-wa-memes/raw/master/imgs/2021年8月14日/20210830161109.png
我想统计所有上传者, 但这个页面上没有相关信息
但是点进去之后可以看到上传者的qq名
https://gitee.com/Arxher/cra-wa-memes/raw/master/imgs/2021年8月14日/20210830161319.png
我想问下有没有什么手段可以用JS脚本直接获取到这个名字...
我JS太菜了 一时想不出来方法

还是说我应该用python爬虫?
我虽然没用过python爬虫 但是好像很强大?

5long 发表于 2021-8-30 16:43

用什么编程语言都行
如果是在浏览器里跑 JS, 那么肯定得学习浏览器的 DOM API
在页面上选择元素用 querySelectorAll
取元素的文本内容用 innerText
具体的 API 文档推荐 MDN https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll

不知道现在有推荐什么 JS 教材
早年自己读过的书是这个 https://book.douban.com/subject/3007076/

aithinkso 发表于 2021-8-30 16:51

这个得从http协议学起了

—— 来自 Xiaomi Redmi K30 5G, Android 11上的 S1Next-鹅版 v2.4.4.1

冰箱研会长e-3M 发表于 2021-8-30 16:53

5long 发表于 2021-8-30 16:43
用什么编程语言都行
如果是在浏览器里跑 JS, 那么肯定得学习浏览器的 DOM API
在页面上选择元素用 querySel ...

基础的DOM我会(吗)
但不是很会

他上一级的页面有相关的信息 我用遍历xpath储存下来了
但到了这一级就没有可以直接获取的信息了
需要点个链接进入下一个frame(是这么说的吗? 这个概念我用的对吗?)
才有信息

就是这个怎么处理我没太懂

凶手 发表于 2021-8-30 16:54

点了之后是重新请求了新页面还是在原页面里面?
还在原页面的话先模拟点击:https://stackoverflow.com/questions/2705583/how-to-simulate-a-click-with-javascript

冰箱研会长e-3M 发表于 2021-8-30 16:54

凶手 发表于 2021-8-30 16:54
点了之后是重新请求了新页面还是在原页面里面?
还在原页面的话先模拟点击:https://stackoverflow.com/que ...

原页面 我看看这个

凶手 发表于 2021-8-30 16:55

冰箱研会长e-3M 发表于 2021-8-30 16:54
原页面 我看看这个

先模拟点击 然后lz你需要的内容就可以用dom api弄出来了吧

5long 发表于 2021-8-30 16:59

冰箱研会长e-3M 发表于 2021-8-30 16:53
基础的DOM我会(吗)
但不是很会



my bad, 没看清主楼是要点击链接, 然后去拿新页面的数据
如果能拿到链接的 href 的话应该可以用 `window.open()`
用新开 window 的 .document 去访问新窗口里的 DOM
再就是可以考虑用 https://github.com/puppeteer/puppeteer 这种真-浏览器爬虫

冰箱研会长e-3M 发表于 2021-8-30 17:00

凶手 发表于 2021-8-30 16:55
先模拟点击 然后lz你需要的内容就可以用dom api弄出来了吧

试了一下 基本差不多了 这个思路可以
稍微加几个sleep等待自动运行就行了

冰箱研会长e-3M 发表于 2021-8-30 17:46

凶手 发表于 2021-8-30 16:55
先模拟点击 然后lz你需要的内容就可以用dom api弄出来了吧

打开新页面之后没法用xpath定位到元素 返回为null
但在js console直接获取就可以...
试着sleep了一下也获取不到... 感觉是我哪里搞错了?Xpath没更新?
但我用document.querySelector(".js-report-click").innerText试了一下也是如此...
我是不是缺少了什么常识性的东西...



function getElementByXpath(path) {
    return document.evaluate(path, document, null,
      XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
//Function to get XPath

function sleep(milliseconds) {
    var start = new Date().getTime();
    for (var i = 0; i < 1e7; i++) {
      if ((new Date().getTime() - start) > milliseconds){
      break;
      }
    }
}

function Reture2TopPage(){
    getElementByXpath("/html/body/div/div/div/div/a").click();
}

function OpenImagePage(NameCounter){
    getElementByXpath(`//li[${NameCounter}]//div//div//div//a//img`).click();
}

var PicCounter = 1;
var NameList = new Array();

while (getElementByXpath(`//li[${PicCounter}]//div//div//div//a//img`)) {
    OpenImagePage(PicCounter);
var UploaderName = getElementByXpath("/html/body/div/div/div/div/div/div/div/div/div/div/div/p/a").innerText;
    NameList.push(UploaderName);
    console.log(`Current Title is : `,UploaderName);
    PicCounter=PicCounter+1;
    Reture2TopPage();
    sleep(1200);
}
console.log(NameList.join("\n"))

凶手 发表于 2021-8-30 17:50

冰箱研会长e-3M 发表于 2021-8-30 17:46
打开新页面之后没法用xpath定位到元素 返回为null
但在js console直接获取就可以...
试着sleep了 ...

为嘛非要用xpath
用的话先试一试 http://xpather.com/

冰箱研会长e-3M 发表于 2021-8-30 17:57

凶手 发表于 2021-8-30 17:50
为嘛非要用xpath
用的话先试一试 http://xpather.com/

document.getElementsByClassName也不成
是不是脚本没应用上页面的变化呢..

5long 发表于 2021-8-30 18:02

JS 是个单线程运行环境, JS 在执行中的时候浏览器是不会渲染页面的(至少早年我学到的是这样, 我已经不写前端很久了)
OpenImagePage() 调用之后会立即返回, 此时页面的内容根本没变. 所以怎么都取不到
所以要把 sleep 加在 OpenImagePage() 的调用之后, 取文本内容之前.

不过话说回来, 同样因为 "JS 是个单线程运行环境", 你这个 busy waiting 式的 sleep() 实现应该会卡住页面. 这也是个问题.
正确的做法是用 setTimeout() 异步地等待

凶手 发表于 2021-8-30 18:47

5long 发表于 2021-8-30 18:02
JS 是个单线程运行环境, JS 在执行中的时候浏览器是不会渲染页面的(至少早年我学到的是这样, 我已经不写前 ...

稍微看了下 lz 的问题在于
列表是在一个 iframe 里面
然后那个有作者名字的反而是在外面 所以 devtools 的 js context 要是 top 的话就模拟不了列表元素的点击 要是 app_canvas_frame 的话就无法得到作者的名字

凶手 发表于 2021-8-30 18:52

冰箱研会长e-3M 发表于 2021-8-30 17:57
document.getElementsByClassName也不成
是不是脚本没应用上页面的变化呢..

js context 是 top 的情况下:
document.getElementById("tphoto").contentDocument.getElementsByClassName("j-pl-photoitem-img").click(); const timer = setTimeout(() => { clearTimeout(timer); console.log(document.querySelector("[data-tag='nickname'").innerText); }, 2500)

lz你可以试试 ok的话照这个思路弄

smishe 发表于 2021-8-30 22:41

可能你需要了解一下xmlhttpRequest

糊状物 发表于 2021-8-30 23:29

楼主会啥语言?基本都不会的话不建议楼主从0开始学爬虫,要学的东西多而且还要面对各种反爬虫,学习曲线有点陡峭。

我没用过qq相册不清楚有无反爬。

Aeroblast 发表于 2021-8-30 23:57

本帖最后由 Aeroblast 于 2021-8-31 00:37 编辑

之前想过抓自己的空间留个档,结果做了一半不了了之了。我这有个其他思路,你看看行不行。
一边模拟点击,一边抓请求。
比如我看到一个user.qzone.qq.com/proxy/domain/photo.qzone.qq.com/fcgi-bin/cgi_floatview_photo_list_v2后面一串参数,内容是json,里面有个photos列表,一个个什么谁发的 上传时间 图片链接(不知道是不是原图)都有。当然这个api不一定行,可能需要找别的,然后还要查重什么的。

js抓这种请求的话,给XMLHttpRequest.prototype.open和send套一层你的抓取。然后qq空间这堆请求返回不是纯json,外面套个函数,什么什么callback,你可以照着写个函数,eval一下在油猴的作用域就调用你自己的这个函数,直接拿到对象。    function viewer_Callback(data){
      console.log(data.data.photos)
    }
    XMLHttpRequest.prototype.openO=XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open=function(method, url, async, user, password){
      this.openO(method, url, async, user, password);
      this.url=url;
    }
    XMLHttpRequest.prototype.sendO=XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.send=function(para){
      this.sendO(para);
      if(this.url.startsWith("https://user.qzone.qq.com/proxy/domain/photo.qzone.qq.com/fcgi-bin/cgi_floatview_photo_list_v2")){
            let onloadO=this.onload;
            this.onload=function(){
                eval(this.responseText);//调用viewer_Callback
                onloadO()
            }
      }
    }
然后你加上模拟点击下一张,遇到一次请求是19个,photos是个数组里面啥也有

冰箱研会长e-3M 发表于 2021-8-31 07:23

糊状物 发表于 2021-8-30 23:29
楼主会啥语言?基本都不会的话不建议楼主从0开始学爬虫,要学的东西多而且还要面对各种反爬虫,学习曲线有 ...

也算是个程序员 但前端啊 浏览器什么的 算是我知识盲区吧
只明白一些轮廓 所以就像这样 具体执行中会遇到很多问题

糊状物 发表于 2021-8-31 08:58

冰箱研会长e-3M 发表于 2021-8-31 07:23
也算是个程序员 但前端啊 浏览器什么的 算是我知识盲区吧
只明白一些轮廓 所以就像这样 具体执行中会遇到 ...

Python或者java比较熟可以用selenium+webdriver,js的话我只用过puppeteer,只是我是业余玩票的,自己只抓过小说和免费代理,我寻思比直接在浏览器里运行脚本要方便多了吧

—— 来自 Xiaomi MI 8, Android 10上的 S1Next-鹅版 v2.4.4.1

SYJMagician 发表于 2021-8-31 21:49

要不用用八爪鱼
页: [1]
查看完整版本: 怎么用JS脚本获取链接内的元素?