QAQ~QL 发表于 2024-2-29 17:33

[Python] 52破解的附件上传小工具

本帖最后由 QAQ~QL 于 2024-3-5 09:28 编辑


# 52破解的附件上传

## 起因

2024春节题,本来用Typora自动picgo传上自己的七牛oss,发到论坛后发现很多地区都无法查看图片,遂手动使用论坛的图片功能传了将近50张图(4个帖子),并从html代码中提取了img的src网址,回到MD中**一一修改了img的网址**(真 ** 累啊)(后来发现自己是真傻啊,哈哈哈哈哈)

https://www.52pojie.cn/misc.php?mod=faq&action=faq&id=29&messageid=36

但是,由于上传图片返回的链接是临时链接,需要传到`附件/图片`点击附件,插入的`xxx`才是永久链接,遂又重新折腾了一遍,改到头皮发麻,于是诞生了该代码

## 代码

环境`pip install requests_toolbelt requests beautifulsoup4`

```python
import random
import string
import xml.etree.ElementTree as ET
from bs4 import BeautifulSoup
from time import sleep

import requests
import re
import os

from requests_toolbelt import MultipartEncoder


# 需要获取的两个数据
# <input type="hidden" name="formhash" value="30c6d8fa">
# <input type="hidden" name="hash" value="0a0d2c087fa9143d3c1eab8e3f3bc138">

# 服务器上传限制    *.rar;*.7z;*.zip;*.txt;*.jpg;*.png

class WuAiPojie:

    # 初始化 ua:浏览器标识,cookie:登录cookie,fid:板块id
    def __init__(self, ua, cookie, fid=2):
      if len(ua) <= 0 | len(cookie) <= 0:
            raise Exception("ua和cookie不能为空")
      self.UA = ua
      self.Cookie = cookie
      self.fid = fid
      self.FormHash = ""
      self.Hash = ""
      self.uid = ""
      self.session = requests.session()
      self.session.headers = {
            "User-Agent": self.UA,
            "Cookie": self.Cookie,
            "Referer": "https://www.52pojie.cn/forum.php?mod=post&action=newthread&fid=2",
            "Origin": "https://www.52pojie.cn",
            "Accept": "*/*"
      }
      # self.session.verify = False
      self.isInit = self.init()

    def init(self):
      try:
            url = 'https://www.52pojie.cn/forum.php?mod=post&action=newthread&fid=' + str(self.fid)
            headers = {
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
            }
            response = self.session.get(url, headers=headers)
            self.FormHash = re.findall(r'<input type="hidden" name="formhash" value="(.*?)"[\s/]*>', response.text)
            self.Hash = re.findall(r'<input type="hidden" name="hash" value="(.*?)"[\s/]*>', response.text)
            self.uid = re.findall(r'<input type="hidden" name="uid" value="(.*?)"[\s/]*>', response.text)
            if len(self.FormHash) | len(self.Hash) | len(self.uid) <= 0:
                raise Exception("获取初始数据失败", response.text)
            # print("初始化成功", self.FormHash, self.Hash, self.uid)
            return True
      except Exception as e:
            raise Exception("获取初始数据失败", e)

    def __init_check__(self):
      if self.isInit is False:
            raise Exception("请先初始化")

    # 上传文件,返回   (附件id,文件名,插入到帖子的标签)
    def upload(self, file, name=""):
      self.__init_check__()
      # 获取文件名和文件类型
      _name, filetype, _type = self.__can_update__(file)
      if len(name) <= 0:
            name = _name

      url = 'https://www.52pojie.cn/misc.php?mod=swfupload&action=swfupload&operation=upload&fid=' + str(self.fid)
      multipart_encoder = MultipartEncoder(
            fields={
                'Filedata': (name, open(file, 'rb'), _type),
                'Filename': (None, name),
                'filetype': (None, filetype),
                'formhash': (None, self.FormHash),
                'uid': (None, self.uid),
                'hash': (None, self.Hash),
            },
            boundary='-----------------------------' + ''.join()
      )
      response = self.session.post(url, data=multipart_encoder, headers={'Content-Type': multipart_encoder.content_type})
      attach_id = response.text
      prefix = "attach"
      if filetype == ".jpg" or filetype == ".png":
            prefix = "attachimg"
      return attach_id, name, "[{0}]{1}[/{2}]".format(prefix, attach_id, prefix)

    # 判断文件是否可以上传,并且返回文件类型和文件名
    def __can_update__(self, file):
      self.__init_check__()
      if not os.path.exists(file):
            raise Exception("文件[" + file + "]不存在")
      file_type = os.path.splitext(file)
      name = os.path.basename(file)
      if file_type in [".rar", ".7z", ".zip", ".txt", ".jpg", ".png"]:
            if file_type == ".zip":
                _type = "application/x-zip-compressed"
            elif file_type == ".png":
                _type = "image/png"
            elif file_type == ".jpg":
                _type = "image/jpeg"
            elif file_type == ".7z" or file_type == ".rar":
                _type = "application/octet-stream"
            else:
                # elif file_type == ".txt":
                _type = "text/plain"
            return name, file_type, _type
      else:
            raise Exception("文件[" + file + "]类型不支持")

    # 删除附件aid: [附件id_1,附件id_2...]返回删除数量
    def delete(self, aid):
      self.__init_check__()
      # 经测试,多文件一起删会导致所有文件都没了
      # url = 'https://www.52pojie.cn/forum.php?mod=ajax&action=deleteattach&inajax=yes&formhash=' + self.FormHash + '&tid=0&pid=0&aids[]=' + '&aids[]='.join(aid)
      num = 0
      for a in aid:
            # 错误重试3次
            for i in range(3):
                try:
                  url = 'https://www.52pojie.cn/forum.php?mod=ajax&action=deleteattach&inajax=yes&formhash=' + self.FormHash + '&tid=0&pid=0&aids[]=' + a
                  response = self.session.get(url)
                  tree = ET.fromstring(response.text)
                  if tree.text != "1":
                        raise Exception("删除附件[" + a + "]失败")
                  num += 1
                  break
                except Exception as e:
                  print(e)
                finally:
                  self.__delay__()
      return num

    # 获取新帖的所有附件   返回附件列表 [(文件名,附件id,是否是图片),...]
    def getfiles(self):
      self.__init_check__()
      url = "https://www.52pojie.cn/forum.php?mod=ajax&action=attachlist&fid=2&inajax=1&ajaxtarget=attachlist"
      response = self.session.get(url)
      _list = []
      # 取出html
      tree = BeautifulSoup(ET.fromstring(response.text).text.split('<script'), 'html.parser')
      # 找class为xi2的a标签,获取文本
      for a in tree.find_all("a", class_='xi2'):
            _list.append((a.text, a.get('id').replace("attachname", ""), bool(a.get('isimage'))))
      return _list

    # 上传文件夹下的所有文件    [(附件id,文件名,插入到帖子的标签),...]
    def upload_folder(self, folder):
      self.__init_check__()
      rs = []
      for file_name in os.listdir(folder):
            # 错误重试3次
            for i in range(3):
                try:
                  _t = self.upload(os.path.join(folder, file_name))
                  rs.append(_t)
                  print(_t)
                  break
                except Exception as e:
                  print(e)
                finally:
                  self.__delay__()
      return rs

    # 接口有限流,慢慢来
    @staticmethod
    def __delay__():
      sleep(1)


if __name__ == '__main__':
    cookie = "填你自己的,记得到发帖的页面拿,切记使用抓包的cookie,不然会报错"
    ua = "填你自己的"

    # 初始化上传类
    t = WuAiPojie(ua, cookie)

    # 遍历当前 ./upload 目录下的文件上传
    t.upload_folder(os.path.abspath('') + os.path.sep + ".." + os.path.sep + "assets")

    # 删除多个附件
    # print(t.delete(["2678878","2678872"]))

    # 获取新帖的所有附件
    print(t.getfiles())

```

***成功样例***



## GUI


环境`pip install PyQt5 pyqt5-tools`

界面如下,代码参看附件








QAQ~QL 发表于 2024-2-29 17:38

依赖环境
pip install requests_toolbelt requests beautifulsoup4

QAQ~QL 发表于 2024-2-29 17:41

Hmily 发表于 2024-2-29 17:38
没看懂,这和网页上有有什么区别?如果附件没有使用插入帖子,也会被定期清理的。

先把一堆文件传附件,然后把原文章的img全部替换上传后的
再开新帖,点击使用,把改完的文章贴进去
还是得把GUI整出来,写个img替换表达式,这两天加工一下

你是神 发表于 2024-2-29 17:37

感谢分享

wasonglili 发表于 2024-2-29 17:38


感谢分享

gy001715 发表于 2024-2-29 17:38

谢谢分享

Hmily 发表于 2024-2-29 17:38

没看懂,这和网页上有有什么区别?如果附件没有使用插入帖子,也会被定期清理的。

xins666 发表于 2024-2-29 17:39

感谢分享

happywff 发表于 2024-2-29 17:44

先复制保存

Hmily 发表于 2024-2-29 17:44

QAQ~QL 发表于 2024-2-29 17:41
先把一堆文件传附件,然后把原文章的img全部替换上传后的
再开新帖,点击使用,把改完的文章贴 ...

把你手动搞错的替换成?那这种工具太小众了可能。
页: [1] 2 3 4 5
查看完整版本: [Python] 52破解的附件上传小工具