小红书爬虫 您所在的位置:网站首页 python爬取小红书 小红书爬虫

小红书爬虫

2023-07-07 12:14| 来源: 网络整理| 查看: 265

小红书爬虫相比于其它静态页面爬虫难度较大,而且互联网上关于小红书爬虫的相关的信息很少。小红书网页版并没有搜索入口,因此网络中大多爬取的方式是通过移动端获取,即通过模拟器(如Nox)和客户端抓包(如Appium)相结合的方式爬取。

由于本人缺乏移动端爬虫的经验,因此本人尝试通过网页进行爬取。网页端爬取通常有两种方式,比较安全的方式是通过request.get()函数抓取网络json内容,另一种比较通用的方式是通过模拟浏览器访问的方式抓取html文件;不过后者的方式爬取速度缓慢且容易被反爬。

在尝试了很多种方式之后,对于本人最终采用了Selenium模拟的方式进行爬取小红书。因为通过request.get()的方式需要request.options()预请求,其中存在x-s, x-t, x-bstraceid三个必填的加密参数,而这三个加密参数并不是恒定不变的,因此获取难度较大。(需要分析Java Script代码,对该文件进行逆向解析才可以,否则小红书Server将会返回{"code":-1,"success":false})而本人对JS语言并没有很熟悉,因此最终采用了模拟浏览器的方法进行爬取小红书。

简单总结一下,网页端爬取小红书的方式大致有如下两种:

通过requests.get()获取网络URL,再次请求该URL获取需要的信息。 通过Selenium模拟浏览器获取HTML,从中搜索需要的信息。 通过网络GET获取文章ID

获取每个文章ID的方式,经过研究发现并没有x-s, x-t, x-bstraceid必填参数的限制,因此可以使用requests.get()的方式进行获取。此方式适合通过寻找#hashtag#的方式获取。获取ID的函数具体实现方式如下:

def find_uid(page_id): url1 = "https://www.xiaohongshu.com/web_api/sns/v3/page/notes" param1 = { 'page_size': 20, # max = 20 'page_id': page_id, 'cursor': None, 'sid': None, } sort = ['hot', 'time'] # 按热度/按时间 param1['sort'] = sort[1] data = dataset() for page in range(51): # 翻页数 max = 1000/page_size response = requests.get(url1, headers=headers, params=param1) resp_json = response.json() text = resp_json["data"]["notes"] cursor = resp_json["data"]["cursor"] param1['cursor'] = cursor # print(cursor) for num in range(len(text)): print(">> ", text[num]["id"], ": ", text[num]["title"]) if text[num]["id"] not in data.id: data.id.append(text[num]["id"]) # uid data.title.append(text[num]["title"]) # title data.like.append(text[num]["likes"]) # likes temp = [] image_list = text[num]["images_list"] # image for photo in range(len(image_list)): temp.append(image_list[photo]["url_size_large"]) data.image.append(temp) sleep(4) return data 通过模拟浏览器获取文章ID

另一种方式便是通过Selenium模拟翻页的方式获取每篇文章的ID信息,此种方式适合获取某个人账号下的所有文章信息。如下图所示,我们希望获取“小熊虫”下面的所有文章ID,如果通过requests.get()方式获取,小红书Server同样会禁止访问{"code":-1,"success":false},因此只能通过模拟的方式进行访问。(如果涉及对该用户信息的侵权,请联系我删除)

小红书对访问时间间隔非常敏感,经测试,5s访问一次就会触发小红书的验证系统,因此普遍访问请求的间隔应该设置在10s左右为佳,且间隔一段时间(如一小时)就应该停止一段时间的访问。

另一个问题就是需要登录小红书账号之后,小红书才会展示更多个人界面下的笔记,否则只能展示前11个笔记。因此每次模拟之前均需要手动扫码登陆自己的小红书,然后刷新界面一次。

Selenium模拟翻页的Python函数如下:

def find_uid(page_id): opt = Options() opt.add_experimental_option("excludeSwitches", ["enable-automation"]) opt.add_experimental_option('useAutomationExtension', False) opt.add_argument('accept-language=zh-CN,zh,zh-TW,en-US,en') opt.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54') opt.add_argument("disable-blink-features=AutomationControlled") driver = webdriver.Chrome(ChromeDriverManager().install(), chrome_options=opt) url0 = "https://www.xiaohongshu.com/user/profile/" + str(page_id) driver.get(url=url0) sleep(30) # s手动登录 ans = [] for i in range(100): uid_list = driver.find_elements(By.XPATH, "//section[@class='note-item']/a[1]") for id in uid_list: url_temp = id.get_attribute('href') if url_temp not in ans: ans.append(url_temp) print(url_temp) driver.execute_script('window.scrollBy(0,document.body.scrollHeight)') sleep(2) print('-' * 50) return ans 获取每篇文章的正文信息

同上,依旧涉及到x-s, x-t, x-bstraceid这三个参数的问题,因此只能通过模拟的方式进行爬取,前面的代码已经可以获取到每篇文章的ID信息,因此只需要不停的访问,然后分析得到的HTML网页就可以啦。过程虽然简单,但是要做好充分的反爬机制,建议挂代理尝试(否则玩坏了本地IP就尴尬了)。找正文和标题等信息还是蛮简单的,第一行HTML代码就是,如图所示。目前本人还在尝试攻克评论信息的获取,欢迎在评论中探讨。

这里有一个问题就是,第一次模拟爬取某一特定文章的时候,小红书会返回空白值。本人一开始以为这小红书的反爬机制做的这么高级,连模拟浏览器都能检测出来,然后拿空白值来屏蔽掉真实的信息,这可太厉害了。但是,后来经过一次偶然的尝试,好像只要手动点击一下刷新就可以了(自动的driver.refresh()还是不行),额…是我想多了(也是经验不足的缘故),不过就是这么一个小小的问题当时就困扰了我好久,所以在此记录一下我的智障时刻(逃)。

通过Selenium模拟浏览器请求的具体代码如下:

opt = Options() opt.add_experimental_option("excludeSwitches", ["enable-automation"]) opt.add_experimental_option('useAutomationExtension', False) opt.add_argument('lang=zh-CN,zh,zh-TW,en-US,en') opt.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54') opt.add_argument("disable-blink-features=AutomationControlled") driver = webdriver.Chrome(ChromeDriverManager().install(), chrome_options=opt) def simulation(uid): # driver.refresh() # 第一次get的时候需要刷新一下refresh!!! driver.get('https://www.xiaohongshu.com/explore/' + str(uid)) sleep(float(random.randint(50, 100) / 10)) # source = driver.page_source try: keyword = driver.find_elements(By.XPATH, "//meta[@name='keywords']") descript = driver.find_elements(By.XPATH, "//meta[@name='description']") # title = driver.find_elements(By.XPATH, "//meta[@name='og:title']") except: return '', '' if keyword[-1].get_attribute('content') != '': return keyword[-1].get_attribute('content'), descript[-1].get_attribute('content') else: return '', '' 全部代码 import os.path import requests import random import openpyxl as op from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from webdriver_manager.chrome import ChromeDriverManager from time import sleep class dataset: def __init__(self): self.id = [] self.image = [] self.like = [] self.read = [] self.title = [] headers = { 'authority': 'www.xiaohongshu.com', 'accept': 'application/json, text/plain, */*', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', 'cookie': 'your cookie...', 'sec-ch-ua': '"Chromium";v="110", "Not A(Brand";v="24", "Microsoft Edge";v="110"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'server-version': 'v2023.02.13.1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.69', # 'x-b3traceid': '4320d4c1abdb0538', # 'x-s': 'sYMK1gc+1l5b1iFi1iqvsl1iOgFL1g9Cs6FLO6TbZj93', # 'x-t': x_t, } def make_img(pos, data): uid = data.id[pos] for num in range(len(data.image[pos])): img = requests.get(data.image[pos][num]).content with open("Image/" + str(uid) + "/" + str(uid) + "_" + str(num) + ".jpg", "wb") as f: f.write(img) sleep(0.5) if __name__ == "__main__": keyword = "5d6b83c3bec183000190c28c" data_list = find_uid(keyword) print(len(data_list.id), len(data_list.title), len(data_list.image)) opt = Options() opt.add_experimental_option("excludeSwitches", ["enable-automation"]) opt.add_experimental_option('useAutomationExtension', False) opt.add_argument('lang=zh-CN,zh,zh-TW,en-US,en') opt.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54') opt.add_argument("disable-blink-features=AutomationControlled") driver = webdriver.Chrome(ChromeDriverManager().install(), chrome_options=opt) wb = op.load_workbook("test.xlsx") ws = wb['Sheet1'] for i in range(len(data_list.id)): if not os.path.exists("Image/" + str(data_list.id[i])): os.makedirs("Image/" + str(data_list.id[i])) # 创建文件夹 keyword, descript = simulation(data_list.id[i]) print("ID:", data_list.id[i]) print("Title:", data_list.title[i]) print("Like:", data_list.like[i]) print("Keyword:", keyword) print("Description:", descript) print("-" * 50) # write to excel d = data_list.id[i], data_list.title[i], data_list.like[i], keyword, descript try: ws.append(d) wb.save("test.xlsx") except: print("Error: Cannot save to Excel!!!") make_img(i, data_list) else: # 之前已经爬取过了 print(">> 爬过的帖子...") continue exit(0)


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有