小红书关键词搜索爬虫

一、简介

一款小红书爬虫工具,可以根据关键词进行搜索下载笔记内容,可以设置搜索条数、搜索内容!
(1)输出表格:博主ID、关键词、三连数、笔记链接等
(2)以笔记标题为目录存储笔记图片;

二、工具设计

工具设计初衷是为了针对小红书运营专员方便进行相关词条进行笔记检索,方便根据三连数、关键词等参数进行快速过来和内容整理,主要是提高该部分从业人员的工作效率,那么主要需要包含以下一个强需求:

  • 要能够有边界的操作界面;
  • 要支持多个过滤参数配置;
  • 要能够支持进行循环中断检索;
  • 要能够有较为清晰的操作提示;

2.1界面设计

离线工具且界面要求简单易操作,这里选择使用Tkinter作为UI开发工具;
采用最简单的网格布局如下:
在这里插入图片描述

根据要求界面设计如下:

在这里插入图片描述

2.2流程设计

2.2.1.明确需求
主要就是能够进行关键词检索后能够拿到各个笔记的URL,通过分析小红书每个笔记的URL其中都用较为固定的ID和token部分,例如:
https://www.xiaohongshu.com/explore/667ad3cf000000001d01530f?xsec_token=ABLSu50SAsII4x9OxuH2KHDa3qraPRWiPww25jEweu7cA=&xsec_source=pc_search&source=web_search_result_notes

其中:667ad3cf000000001d01530f为ID
ABLSu50SAsII4x9OxuH2KHDa3qraPRWiPww25jEweu7cA=为token

2.2.2.抓包分析
通过抓包分析和过滤发现,例如根据上述token来进行搜索,会发现在这条web/v1/search/notesURL中会有上述两个字段的返回记录,那么我们可以断定该条URL的返回请求肯定包含着大量的被检索出的笔记URL;
在这里插入图片描述
于是针对关键词检索时的所有URL进行过滤发现,与预期一致:
在这里插入图片描述
2.2.3.发送请求

  1. 关键词搜索
    由于小红书官网限制针对关键词搜索时必须进行登录后才能操作,那么通过抓包分析发现小红书请求标头有两个字段X-s和X-S-Common无法直接模拟获取(需要能够掌握逆向技术),那么这个就大大提高的爬虫门槛;
    在这里插入图片描述
    那么针对这种情况,我们想到了DrissionPage通过真实的用户登录操作来实现该步骤!

这里的DrissionPage在使用前一定要先设置下他的启动路径,但是只要设置一次就够了!

from DrissionPage import ChromiumOptions
path = r'D:\my_chrome_path\chrome.exe'	# 这里设置你自己电脑的chrome可执行程序路径
ChromiumOptions.set_browser_path(path).save()
  1. 笔记内容请求
    由于单独请求和访问某条笔记内容链接无需登录操作,那么我们可以直接使用老办法request来进行模拟请求!

2.2.4.获取解析数据

  1. 通过元素面板定位数据标签来获取数据内容;
  2. 监听数据包获取响应数据(推荐);

2.2.5.保存数据
笔记内容等文字数据存储到表格中,图片直接写入固定目录中;这里采用openpyxl来操作表格。

三、代码实现

3.1.界面代码实现

import tkinter as tk
from tkinter import ttk
import threading

# 设置全局字体主题
font_style = {
    'family': '微软雅黑',
    'size': 12,
    'weight': 'bold'
}

# tkinter主体
root = tk.Tk()
root.title("小红书爬虫")
root.eval('tk::PlaceWindow . center')  # 居中窗口
root.resizable(False, False)  # 禁用窗口大小调整

# 第一行
tk.Label(root, text="关键词", font=font_style).grid(row=0, column=0, padx=5, pady=5)
keyword = tk.Entry(root)
keyword.insert(0, "大有泰")
keyword.grid(row=0, column=1, columnspan=4, padx=5, pady=5, sticky="ew")

# 第二行 搜索上限 和 配置项
tk.Label(root, text="搜索上限", font=font_style).grid(row=1, column=0, padx=5, pady=5)
limitcount = tk.Entry(root)
limitcount.insert(0, "50")
limitcount.grid(row=1, column=1, padx=5, pady=5)

# 默认:博主、内容、关键词
# 可选:三连、图片、链接
sanlian_var = tk.BooleanVar(value=True)
tk.Checkbutton(root, text="三连", variable=sanlian_var, font=font_style).grid(row=1, column=2, sticky="w")

pic_var = tk.BooleanVar(value=True)
tk.Checkbutton(root, text="图片", variable=pic_var, font=font_style).grid(row=1, column=3, sticky="w")

link_var = tk.BooleanVar(value=True)
tk.Checkbutton(root, text="链接", variable=link_var, font=font_style).grid(row=1, column=4, sticky="w")

# 第三行   搜索进度
tk.Label(root, text="搜索进度", font=font_style).grid(row=2, column=0, padx=5, pady=5)
progress_bar = ttk.Progressbar(root, mode="determinate")
progress_bar.grid(row=2, column=1, columnspan=3, padx=5, pady=5, sticky="ew")
progress_text = tk.StringVar(value="0%")
tk.Label(root, textvariable=progress_text, font=font_style).grid(row=2, column=4, padx=5, pady=5)

# 全局参数
stop_event = threading.Event() # 设置线程事件用于控制线程启停
running_thread = None  # 保存线程对象

# 主线程 -- 具体内容在下一部分实现
def long_task():
	pass

# 启停按钮处理函数
def btn_func():
    global running_thread
    thread_param = {}
    if btn_var.get() == "开始":
        if keyword.get() == "":
            messagebox.showerror("错误", "请输入搜索关键词")
            return
        btn_var.set("结束")
        keyword.config(state="disable")
        if not running_thread or not running_thread.is_alive():
            stop_event.clear()  # 重置停止标志
            progress_bar['value'] = 0 # 初始化进度条值
            running_thread = threading.Thread(target=long_task, daemon=True)
            running_thread.start()
            mesg_text.set("开始")
    else:
        btn_var.set("开始")
        keyword.config(state="normal")
        if running_thread and running_thread.is_alive():
            stop_event.set()  # 设置停止标志


# 第四行 启停按钮
btn_var = tk.StringVar()
btn_var.set("开始")
tk.Button(root, textvariable=btn_var, command=btn_func, font=font_style).grid(row=3, column=0, columnspan=5, padx=5, pady=5, sticky="ew")


# 第五行 动态变化提示信息
mesg_text = tk.StringVar(value="就绪")
tk.Label(root, textvariable=mesg_text).grid(row=4, column=0, columnspan=5, padx=5, pady=5, sticky="w")

root.mainloop()

3.2.内容爬取代码实现

# 导入数据请求模块
import requests
# 导入正则表达式模块
import re
# 导入文件操作模块
import os
# 导入自动化模块
from DrissionPage import ChromiumPage
# 导入url编码模块
from urllib.parse import quote

# 打开浏览器 (实例化浏览器对象)
g_browser_handle = ChromiumPage()
# 监听数据包-用于获取根据关键词返回的所有笔记URL
g_browser_handle.listen.start('web/v1/search/notes')

# 模拟浏览器请求单个笔记URL的标头
headers = {
    # cookies
    'Cookie': 'code your cookie here',
    # referer 防盗链, 请求网址从哪里跳转过来
    'referer': req_url,
    # user-agent 用户代理, 表示浏览器/设备基本身份信息
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 '
                  'Safari/537.36 '
}

# 关键词输入
key_word = "python爬虫"
key_word_url = quote(key_word)
req_url = f"https://www.xiaohongshu.com/search_result?keyword={key_word_url}&source=web_explore_feed&type=51"
# 访问网站
g_browser_handle.get(req_url)
# 等待数据包加载
r = g_browser_handle.listen.wait()
# 获取响应数据 -> 字典数据
json_data = r.response.body
# 键值对取值, 提取ID和token所在列表
items = json_data['data']['items']
print(f"搜索条数:{len(items)}")

# 判断文件夹是否存在--用于存储图片
if not os.path.exists('img'):
    os.mkdir('img')
# for循环遍历, 提取列表里面的元素
for item in items:
    try:
        # 提取ID
        id_ = item['id']
        # 提取博主昵称
        uper = item['note_card']['user']['nick_name']
        print(f"uper:{uper}")
        # 提取token
        token = item['xsec_token']
        # 单个笔记的请求网址
        url = f'https://www.xiaohongshu.com/explore/{id_}?xsec_token={token}&xsec_source=pc_search'
        print(url)
        # 发送请求
        response = requests.get(url=url, headers=headers)
        """获取数据"""
        # 获取响应的文本数据
        html = response.text
        """解析数据"""
        # 提取帖子标题
        old_title = re.findall('<meta name="og:title" content="(.*?)">', html)[0]
        # 替换特殊字符
        title = re.sub(r'[\\/:*?"<>|\n]', ' ', old_title)
        #print(old_title)
        # 提取帖子内容
        note_content = re.findall('<meta name="description" content="(.*?)">', html)[0]
        # 提取帖子关键词
        note_keywords = re.findall('<meta name="keywords" content="(.*?)">', html)[0]
        # 提取帖子点赞数
        note_like = re.findall('<meta name="og:xhs:note_like" content="(.*?)">', html)[0]
        # 提取帖子收藏数
        note_collect = re.findall('<meta name="og:xhs:note_collect" content="(.*?)">', html)[0]
        # 提取帖子评论数
        note_comment = re.findall('<meta name="og:xhs:note_comment" content="(.*?)">', html)[0]
        print(f"Like:{note_like} Collect:{note_collect} Comment:{note_comment}")
        print(f"-----------------------------------------------------------------------")
        # 提取帖子图片链接
        img_list = re.findall('<meta name="og:image" content="(.*?)">', html)
        # 定义序号
        num = 1
        # for循环遍历, 提取列表里面的元素内容
        for img in img_list:
            # 对于图片链接发送请求, 获取二进制数据
            img_content = requests.get(url=img).content
            # 数据保存
            with open('img\\' + title + str(num) + '.jpg', 'wb') as f:
                # 写入数据
                f.write(img_content)
            num += 1

    except Exception as e:
        print(e)

该部分逻辑只实现了首次打开关键词搜索页面时的数据获取,但是大部分网址都会随着页面侧面滑条下滑动态请求新的数据,那么小红书也是同样的原理,所以为了获取更多的数据,我们还需要实现滑条下滑的动作!

from DrissionPage.common import Actions
from DrissionPage import ChromiumPage
# 打开浏览器 (实例化浏览器对象)
g_browser_handle = ChromiumPage()
ac = Actions(dp)
# 监听数据包
g_browser_handle.listen.start('web/v1/search/notes')
# 获取前5页数据
for page in range(5):
	g_browser_handle.listen.wait()
	print("processing...")
	# 滑条向下滑动1500像素
	ac.scroll(delta_y=1500)

3.3.总体实现

以上3.2的爬虫部分放在3.1部分中long_task就可以实现根据按钮进行启停关键词搜索;完整项目代码请移步木易师傅!!

爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的工作流程包括以下几个关键步骤: URL收集: 爬虫从一个或多个初始URL开始,递归或迭代地发现新的URL,构建一个URL队列。这些URL可以通过链接分析、站点地图、搜索引擎等方式获取。 请求网页: 爬虫使用HTTP或其他协议向目标URL发起请求,获取网页的HTML内容。这通常通过HTTP请求库实现,如Python中的Requests库。 解析内容: 爬虫对获取的HTML进行解析,提取有用的信息。常用的解析工具有正则表达式、XPath、Beautiful Soup等。这些工具帮助爬虫定位和提取目标数据,如文本、图片、链接等。 数据存储: 爬虫将提取的数据存储到数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。 遵守规则: 为避免对网站造成过大负担或触发反爬虫机制,爬虫需要遵守网站的robots.txt协议,限制访问频率和深度,并模拟人类访问行为,如设置User-Agent。 反爬虫应对: 由于爬虫的存在,一些网站采取了反爬虫措施,如验证码、IP封锁等。爬虫工程师需要设计相应的策略来应对这些挑战。 爬虫在各个领域都有广泛的应用,包括搜索引擎索引、数据挖掘、价格监测、新闻聚合等。然而,使用爬虫需要遵守法律和伦理规范,尊重网站的使用政策,并确保对被访问网站的服务器负责。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值