Merge branch 'main' into arknights

This commit is contained in:
felinae98 2021-02-27 14:05:30 +08:00
commit bd078e233d
No known key found for this signature in database
GPG Key ID: 00C8B010587FF610
6 changed files with 98 additions and 4 deletions

View File

@ -30,6 +30,7 @@
## 使用方法 ## 使用方法
### 使用以及部署 ### 使用以及部署
**!!本项目需要Python3.9及以上**
本项目可作为单独插件使用仅包含订阅相关功能绝对simple和stupid也可直接克隆项目进行使用包含自动同意superuser自动接受入群邀请等功能 本项目可作为单独插件使用仅包含订阅相关功能绝对simple和stupid也可直接克隆项目进行使用包含自动同意superuser自动接受入群邀请等功能
作为插件使用请安装`nonebot-hk-reporter`包,并在`bot.py`中加载`nonebot_hk_reporter`插件;或直接克隆本项目进行使用 作为插件使用请安装`nonebot-hk-reporter`包,并在`bot.py`中加载`nonebot_hk_reporter`插件;或直接克隆本项目进行使用
配置与安装请参考[nonebot2文档](https://v2.nonebot.dev/) 配置与安装请参考[nonebot2文档](https://v2.nonebot.dev/)
@ -77,6 +78,12 @@ go-cqhttp镜像可使用`felinae98/go-cqhttp-ffmpeg`(数据目录为`/data`
* 通过图片发送文本,防止风控 * 通过图片发送文本,防止风控
* 使用队列限制发送频率 * 使用队列限制发送频率
# FAQ
1. 报错`TypeError: 'type' object is not subscriptable`
本项目使用了Python 3.9的语法请将Python版本升级到3.9及以上推荐使用docker部署
2. bot不理我
请确认自己是群主或者管理员,并且检查`COMMAND_START`环境变量是否设为`[""]`
## 鸣谢 ## 鸣谢
* [`go-cqhttp`](https://github.com/Mrs4s/go-cqhttp):简单又完善的 cqhttp 实现 * [`go-cqhttp`](https://github.com/Mrs4s/go-cqhttp):简单又完善的 cqhttp 实现
* [`NoneBot2`](https://github.com/nonebot/nonebot2):超好用的开发框架 * [`NoneBot2`](https://github.com/nonebot/nonebot2):超好用的开发框架

View File

@ -1,6 +1,7 @@
from .bilibili import Bilibili from .bilibili import Bilibili
from .rss import Rss from .rss import Rss
from .weibo import Weibo from .weibo import Weibo
from .wechat import Wechat
from .utils import check_sub_target from .utils import check_sub_target
from .platform import PlatformNoTarget from .platform import PlatformNoTarget
from .utils import platform_manager from .utils import platform_manager

View File

@ -6,6 +6,7 @@ from .arkninghts import Arknights
from .weibo import Weibo from .weibo import Weibo
from .bilibili import Bilibili from .bilibili import Bilibili
from .rss import Rss from .rss import Rss
from .wechat import Wechat
from .platform import PlatformProto from .platform import PlatformProto
from ..config import Config from ..config import Config
from ..post import Post from ..post import Post
@ -19,6 +20,7 @@ platform_manager: dict[str, PlatformProto] = {
'weibo': Weibo(), 'weibo': Weibo(),
'rss': Rss(), 'rss': Rss(),
'arknights': Arknights() 'arknights': Arknights()
'wechat': Wechat(),
} }
async def fetch_and_send(target_type: str): async def fetch_and_send(target_type: str):

View File

@ -0,0 +1,75 @@
from datetime import datetime
import hashlib
import json
import re
from typing import Any, Optional
from bs4 import BeautifulSoup as bs
import httpx
from ..post import Post
from ..types import *
from .platform import Platform
class Wechat(Platform):
categories = {}
enable_tag = False
platform_name = 'wechat'
@classmethod
def _get_query_url(cls, target: Target):
return 'https://weixin.sogou.com/weixin?type=1&s_from=input&query={}&ie=utf8&_sug_=n&_sug_type_='.format(target)
@classmethod
async def _get_target_soup(cls, target: Target) -> Optional[bs]:
target_url = cls._get_query_url(target)
async with httpx.AsyncClient() as client:
res = await client.get(target_url)
soup = bs(res.text, 'html.parser')
blocks = soup.find(class_='news-list2').find_all('li',recursive=False)
for block in blocks:
if block.find(string=[target]):
return block
@classmethod
async def get_account_name(cls, target: Target) -> Optional[str]:
if not (block := await cls._get_target_soup(target)):
return None
return block.find('p', class_='tit').find('a').text
async def get_sub_list(self, target: Target) -> list[RawPost]:
block = await self._get_target_soup(target)
if (last_post_dt := block.find('dt', string='最近文章:')):
post = {
'title': last_post_dt.find_parent().find('a').text,
'target': target,
'page_url': self._get_query_url(target),
'name': block.find('p', class_='tit').find('a').text
}
return [post]
else:
return []
def get_id(self, post: RawPost) -> Any:
return post['title']
def get_date(self, post: RawPost):
return None
def get_tags(self, post: RawPost):
return None
def get_category(self, post: RawPost):
return None
async def parse(self, raw_post: RawPost) -> Post:
# TODO get content of post
return Post(target_type='wechat',
text='{}\n详细内容请自行查看公众号'.format(raw_post['title']),
target_name=raw_post['name'],
pics=[],
url=''
)

View File

@ -22,6 +22,10 @@ async def rss_check():
async def arknights_check(): async def arknights_check():
await fetch_and_send('arknights') await fetch_and_send('arknights')
@scheduler.scheduled_job('interval', seconds=30)
async def wechat_check():
await fetch_and_send('wechat')
@scheduler.scheduled_job('interval', seconds=1) @scheduler.scheduled_job('interval', seconds=1)
async def _(): async def _():
await do_send_msgs() await do_send_msgs()

View File

@ -1,10 +1,11 @@
import os import os
import asyncio import asyncio
from typing import Optional from typing import Awaitable, Callable, Optional
import nonebot import nonebot
from nonebot import logger from nonebot import logger
import base64 import base64
from pyppeteer import launch from pyppeteer import launch
from pyppeteer.page import Page
from pyppeteer.chromium_downloader import check_chromium, download_chromium from pyppeteer.chromium_downloader import check_chromium, download_chromium
from html import escape from html import escape
from hashlib import sha256 from hashlib import sha256
@ -19,7 +20,7 @@ class Singleton(type):
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls] return cls._instances[cls]
supported_target_type = ('weibo', 'bilibili', 'rss', 'arknights') supported_target_type = ('weibo', 'bilibili', 'rss', 'arknights', 'wechat')
if not plugin_config.hk_reporter_use_local and not check_chromium(): if not plugin_config.hk_reporter_use_local and not check_chromium():
os.environ['PYPPETEER_DOWNLOAD_HOST'] = 'http://npm.taobao.org/mirrors' os.environ['PYPPETEER_DOWNLOAD_HOST'] = 'http://npm.taobao.org/mirrors'
@ -30,14 +31,18 @@ class Render(metaclass=Singleton):
def __init__(self): def __init__(self):
self.lock = asyncio.Lock() self.lock = asyncio.Lock()
async def render(self, url: str, viewport: Optional[dict] = None, target: Optional[str] = None) -> str: async def render(self, url: str, viewport: Optional[dict] = None, target: Optional[str] = None,
operation: Optional[Callable[[Page], Awaitable[None]]] = None) -> str:
async with self.lock: async with self.lock:
if plugin_config.hk_reporter_use_local: if plugin_config.hk_reporter_use_local:
browser = await launch(executablePath='/usr/bin/chromium', args=['--no-sandbox']) browser = await launch(executablePath='/usr/bin/chromium', args=['--no-sandbox'])
else: else:
browser = await launch(args=['--no-sandbox']) browser = await launch(args=['--no-sandbox'])
page = await browser.newPage() page = await browser.newPage()
await page.goto(url) if operation:
await operation(page)
else:
await page.goto(url)
if viewport: if viewport:
await page.setViewport(viewport) await page.setViewport(viewport)
if target: if target: