前端可视化(一) - 不抓包怎么直接从页面获取数据

1,337 阅读5分钟

前段时间玩「信长之野望·新生」(已天下布武),开局的地图我很喜欢。

各种大名、城池、武将等数据摆放在那里,给赛博斗蛐蛐增添了无尽遐想。所以就有了这样一个念头,把我掘金中关注的朋友一些数值获取到,然后通过地图可视化的方式写一个群雄割据图。

Just for fun :计划创建一个 BI 看板,像争霸割据一样图形化社区相关活跃度,给自己账号运营创造些动力与趣味性,毕竟今年给自己立了个 Flag:去码头整点薯条(1000粉养成计划)

截屏2024-04-29 13.26.51.png

一、拆解逻辑

首先,核心逻辑经过拆分,比较清晰:拿到数据,实现地图容器,数据映射填入,每天定时更新。

其次,可能需要再锦上添花,实现一些设定逻辑,比如:

  • 掘力值(土地面积)
  • 关注数(兵力值)
  • 名称写个随机颜色映射逻辑(势力颜色)
  • 从评论区拿点有趣点子 ...

二、数据获取

今天是第一篇,所以只基于页面的数据获取开展讨论

如果我只关注了 5 个人,那其实手动维护数据都可以。

只要每天点击关注博主的主页里,把相关数据 CV 更新到数据表里,相应网站重新部署下就行。

但哥们好歹是个工程师,实现方式就别这么 Low 了,况且我本身关注的人也很多,工作能自动化的就要自动化掉。回到数据获取的话题上,可以发现我们需要获取的数据有两类:

  • 用户基础数据:掘力值、关注数、被关注数 ...
  • 关注用户列表:关注了哪些人,这个列表是个动态的

下面会介绍不通过抓包,如何直接从页面获取这两类数据的方式

01 | 用户基础数据

用户基础数据相对是比较好获取的,傻瓜一点的方式就是直接抓 html 页面元素值即可:

截屏2024-04-29 13.39.49.png

i. 开发思路

  1. 创建一个 requests 会话
  2. 发起 GET 请求,获取目标网页的内容
  3. 使用 BeautifulSoup 解析获取到的 HTML
  4. 通过 CSS 选择器找到目标元素,提取文本内容
  5. 将数字列表转换为字符串格式并打印

ii. 代码实现

下面这段 python 代码,定义了两个函数。一个是抓取页面中关注相关数据、一个数抓取用户基础数据。实现方式类似,都是通过css选择器定位元素并获取的。

import requests
from bs4 import BeautifulSoup

session = requests.Session() # 创建会话

# 获取关注和关注者数量
def get_followers(url):
    response = session.get(url)
    soup = BeautifulSoup(response.text, "html.parser")
    follow_items = soup.find_all("a", {"class": "follow-item"})
    
    following = []
    followers = []
    for follow_item_index, follow_item in enumerate(follow_items):
        item_count = int(
            follow_item.find("div", {"class": "item-count"}).get_text().strip()
        )
        if follow_item_index % 2 == 0:
            following.append(item_count)
        else:
            followers.append(item_count)
    following_str = ", ".join(map(str, following))
    followers_str = ", ".join(map(str, followers))
    return following_str, followers_str


# 获取基础数据
def get_baseData(url):
    response = session.get(url)
    soup = BeautifulSoup(response.text, "html.parser")
    baseBlock = soup.find("div", {"class": "block-body"})
    counts = baseBlock.find_all("span", {"class": "count"})
    data = {}
    if len(counts) >= 3:
        data["likes"] = counts[0].get_text().strip()
        data["reads"] = counts[1].get_text().strip()
        data["jueli"] = counts[2].get_text().strip()
    return data

# 需替换为你想要抓取的作者页面 URL
url = "https://juejin.cn/user/1591748568038823"  

# 获取关注数据,并输出
following_str, followers_str = get_followers(url)
print(f"following: {following_str}")
print(f"followers: {followers_str}")

# 获取基础数据,并输出
baseData = get_baseData(url)
print(baseData)

运行结果

02 | 关注列表数据

这个难度稍微高一点,因为掘金关注列表有滚动加载,所以需要模拟用户翻页的行为才能获取到全部关注,用 Network 查接口也行,但字段太多不想一个个翻。

如果有知道简便实现方式的老哥欢迎评论区分享,大家一起讨论下。

i. 开发思路

  1. 用户输入的 URL
  2. 使用 selenium 库启动 Chrome 浏览器并打开指定的 URL
  3. 通过滚动和检查页面高度变化来加载所有关注用户
  4. 使用 CSS 选择器定位并提取关注用户的信息
  5. 将提取到的用户信息保存到新文件中

ii. 代码实现

下面的代码实现方式基于用户基础数据的获取方式,额外新增了一个用户翻页行为模拟。用来抓一些加载翻页表单。并将表单中抓取的数据存储到一个txt文件中:

import argparse
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By


# 获取用户关注列表(处理加载与翻页)
def get_my_following(url):
    # 设置WebDriver路径
    webdriver_service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=webdriver_service)

    driver.get(url)

    # 滚动页面直到没有新的用户加载
    last_height = driver.execute_script("return document.body.scrollHeight")
    while True:
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(2)  # 等待新的用户加载
        new_height = driver.execute_script("return document.body.scrollHeight")
        if new_height == last_height:  # 如果没有新的用户加载,停止滚动
            break
        last_height = new_height

    following_users = driver.find_elements(By.CSS_SELECTOR, "ul.tag-list a.username")
    following_list = [user.text for user in following_users]

    driver.quit()

    return following_list


# 新建 or 覆盖,保存用户关注列表
def save_following_to_file(following_list, filename):
    with open(filename, "w") as f:
        for user in following_list:
            f.write(user + "\n")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Get the list of users you are following on Juejin."
    )
    parser.add_argument("url", help="The URL of your following list on Juejin.")
    args = parser.parse_args()

    following_list = get_my_following(args.url)
    length = len(following_list)
    print("关注用户数:", length)

    # 保存关注的用户到文件
    save_following_to_file(following_list, "following.txt")

运行结果

三、功能封装

python 依赖和环境安装挺麻烦还容易报错,所以我这里对模块使用做了一层封装。

感兴趣的朋友你 pull 到本地就能用。

项目地址:github.com/Trade-Offf/…

01 | 使用方法

  • 添加脚本权限: chmod +x install_and_run.sh

clone 仓库后只用执行一次,脚本有了执行权限,你就可以直接运行它,无需再次使用 chmod 命令。

  • 导出关注列表: ./install_and_run.sh (URL-待替换)

其中 URL 是需要导出的关注页,如:https://juejin.cn/user/1591748568038823/following

四、可视化容器(TODO)

下一节实现地图容器,看了这个原神哥的文章,大受启发:

截屏2024-04-29 13.51.59.png

参考文档:让 web 再次伟大——用 canvaskit 实现超级丝滑的原神地图(已开源)