Examples

This page provides a collection of examples of aioqzone usage.

Login

from aioqzone.api import QrLoginConfig, QrLoginManager
from qqqr.utils.net import ClientAdapter

with ClientAdapter() as client:
    mgr = QrLoginManager(client, config=QrLoginConfig(uin=env.uin))

User-Agent is automatically set when login.

from aioqzone.api import UpLoginConfig, UpLoginManager
from qqqr.utils.net import ClientAdapter

with ClientAdapter() as client:
    mgr = UpLoginManager(
        client,
        config=UpLoginConfig.model_validate(
            dict(uin=env.uin, pwd=env.password, fake_ip="8.8.8.8")
        ),
    )

User-Agent is automatically set when login.

You can surely disable auto login and use external cookie:

import json
from os import environ

from aioqzone.api.login import ConstLoginMan
from qqqr.utils.net import ClientAdapter

with open("your_external_cookie.json") as f:
    cookie = json.load(f)
with ClientAdapter() as client:
    mgr = ConstLoginMan(cookie)

User-Agent is NOT automatically set, remember to change it:

from qqqr.utils.net import ClientAdapter
from qqqr.utils.net import use_mobile_ua

with ClientAdapter() as client:
    use_mobile_ua(client)

...

If you'd like to use external cookie with auto login, just assign cookie dict to login manager:

import json
from os import environ

from aioqzone.api.login import QrLoginManager
from qqqr.utils.net import ClientAdapter

with open("your_external_cookie.json") as f:
    cookie = json.load(f)
with ClientAdapter() as client:
    mgr = QrLoginManager(client, config=QrLoginConfig(uin=env.uin))
    mgr.cookie = cookie  # assign external cookie to login manager

Receiving Messages from Login Manager

参见

消息

You can receive QR code image from QR code login manager:

import io

from PIL import Image as image

man = QrLoginManager(client, config=QrLoginConfig(uin=env.uin))
man.qr_fetched.add_impl(
    lambda png, times, qr_renew=False: image.open(io.BytesIO(png)).show() if png else None
)

Create Qzone H5 API

from aioqzone.api import QzoneH5Api
from aioqzone.api.login import QrLoginManager
from qqqr.utils.net import ClientAdapter

with ClientAdapter() as client:
    mgr = QrLoginManager(client, config=QrLoginConfig(uin=env.uin))
    api = QzoneH5Api(client, mgr)
from aioqzone.api import UpLoginConfig, UpLoginManager
from qqqr.utils.net import ClientAdapter

with ClientAdapter() as client:
    mgr = UpLoginManager(
        client,
        config=UpLoginConfig.model_validate(
            dict(uin=env.uin, pwd=env.password, fake_ip="8.8.8.8")
        ),
    )
    api = QzoneH5Api(client, mgr)

fetch feed flow

feed_flow = await api.index()
feed_flow = await api.profile(uin=123456789)

Fetching (self) feed flow is a preliminary step for most operations, as it gets qzonetoken from Qzone server, which is used in most operations.

fetch next page of feed flow

As feed flow is paginated, you can fetch next page of feed flow:

attach_info = None
while True:
    resp = await api.get_active_feeds(attach_info=attach_info)
    attach_info = resp.attach_info
    if not resp.has_more:
        break
attach_info = None
while True:
    resp = await api.get_feeds(uin=123456789, attach_info=attach_info)
    attach_info = resp.attach_info
    if not resp.has_more:
        break

参见

aioqzone-feed provides a high-level interface for fetching feed flow.

fetch avatar from uin

This is a no-login API, you can fetch avatar without login state.

size = 100  # avatar size, can be 100, 640
resp = await api.avatar(123456789, size)
with open("out/avatar.png", "wb") as f:
    f.write(resp.avatar)

upload photo

Uploading photo is a two-step process. The first is QzoneH5API.upload_pic(), which should be called per-image. The response is file length and md5. The second is :meth:`QzoneH5API.preupload_photos , which is called once for multiple images, and the response is a list of PicInfo, including image url, image id, etc.

import asyncio

images = ["image_a.jpg", "image_b.jpg", "image_c.jpg"]
hashes = await asyncio.gather(
    *map(api.upload_pic, images)
)
pic_infos = await api.preupload_photos(hashes)

提示

You can specify quality of uploaded image by setting quality parameter of QzoneH5API.upload_pic().

Mood operation

upload mood

from aioqzone.model import UgcRight

MOOD_TEXT = "Hello, world!"
picinfo = [...]  # list of PicInfo, can be empty
feed = await api.publish_mood(
    MOOD_TEXT, photos=picinfo, sync_weibo=False, ugc_right=UgcRight.self
)

提示

You can specify mood visibility by setting ugc_right parameter of QzoneH5API.publish_mood() .

delete mood

# get appid from fetch feed. common appid of mood without sharing is 311.
delete_response = await api.delete_ugc(feed.fid, appid)

get mood detail

# fetching feed
feed_flow = await api.get_active_feeds()
feed_dict = {i.fid: i for i in feed_flow.vFeeds}
fetched_feed = feed_dict[feed.fid]

detail = await api.shuoshuo(
    fetched_feed.fid, fetched_feed.userinfo.uin, fetched_feed.common.appid
)

like/unlike mood

from aioqzone.model import LikeData

# get appid, curkey and unikey from fetch feed
# common appid of mood without sharing is 311.

# for feeds without forward, curkey and unikey are the same.
# you can construct them by host uin and fid:
# unikey = LikeData.persudo_unikey(appid, hostuin, feed.fid)

await api.internal_dolike_app(appid, unikey, curkey=unikey, like=True)  # like
await api.internal_dolike_app(appid, unikey, curkey=unikey, like=False) # unlike

mood comment

add comment

COMMENT_TEXT = "Nice mood!"
comment = await api.add_comment(
    hostuin, feed.fid, appid, COMMENT_TEXT, busi_param=fetched_feed.operation.busi_param
)

小技巧

busi_param is optional, but recommended.

COMMENT_TEXT = "Nice mood!"
picinfo = [...]  # list of PicInfo
comment_pic = await api.add_comment(
    hostuin, feed.fid, appid, COMMENT_TEXT, [i.url for i in picinfo]
)

注意

Picture comment uses legacy html Qzone API, which has a html response. Currently commentId cannot be parsed from the response.

delete comment

await api.delete_comment(ownuin, fetched_feed.topicId, comment.commentid)

check feed update

Speculation

Call this api every 5 minutes might keep your login cookie alive within one day (or several days). Otherwise the login state will expire in several hours.

await api.mfeeds_get_count()