init code

This commit is contained in:
johlanse 2021-11-12 15:46:33 +08:00
commit 28d0a19069
30 changed files with 1896 additions and 0 deletions

51
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,51 @@
name: CI
on: [push, pull_request]
env:
BINARY_PREFIX: "study_xxqg_"
BINARY_SUFFIX: ""
PR_PROMPT: "::warning:: Build artifact will not be uploaded due to the workflow is trigged by pull request."
LD_FLAGS: "-w -s"
jobs:
build:
name: Build binary CI
runs-on: ubuntu-latest
strategy:
matrix:
# build and publish in parallel: linux/386, linux/amd64, windows/386, windows/amd64, darwin/amd64, darwin/arm64
goos: [linux, windows]
goarch: [amd64]
exclude:
- goos: darwin
goarch: arm
- goos: darwin
goarch: "386"
- goos: windows
goarch: arm64
fail-fast: true
steps:
- uses: actions/checkout@v2
- name: Setup Go environment
uses: actions/setup-go@v2.1.3
with:
go-version: 1.17
- name: Build binary file
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
IS_PR: ${{ !!github.head_ref }}
run: |
if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
if $IS_PR ; then echo $PR_PROMPT; fi
export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"
export CGO_ENABLED=0
go build -o "output/$BINARY_NAME" -ldflags "-w -s -X main.VERSION=action"
- name: Upload artifact
uses: actions/upload-artifact@v2
if: ${{ !github.head_ref }}
with:
name: ${{ matrix.goos }}_${{ matrix.goarch }}
path: output/

41
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: release
on:
push:
tags:
- 'v*'
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: '1.17.2'
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
env:
# main: ./example/main.go
GITHUB_TOKEN: ${{ secrets.TOKEN }}
#- name: Checkout Dist
# uses: actions/checkout@v2
# with:
# repository: 'gocq/dist'
# ref: master
# ssh-key: ${{ secrets.SSH_KEY }}
# path: upstream/dist
#- name: Update Dist
# run: |
# chmod +x scripts/upload_dist.sh
# ./scripts/upload_dist.sh

94
.golangci.yml Normal file
View File

@ -0,0 +1,94 @@
linters-settings:
errcheck:
ignore: fmt:.*,io/ioutil:^Read.*
ignoretests: true
goimports:
local-prefixes: github.com/huoxue1/study_xxqg
gocritic:
disabled-checks:
- exitAfterDefer
forbidigo:
# Forbid the following identifiers
forbid:
- ^fmt\.Errorf$ # consider errors.Errorf in github.com/pkg/errors
linters:
# please, do not use `enable-all`: it's deprecated and will be removed soon.
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
fast: true
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- exportloopref
- exhaustive
#- funlen
#- goconst
- gocritic
#- gocyclo
- gofmt
- goimports
- goprintffuncname
#- gosec
- gosimple
- govet
- ineffassign
- misspell
- nolintlint
- rowserrcheck
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
- prealloc
- predeclared
- asciicheck
- forbidigo
- makezero
- revive
#- interfacer
# don't enable:
# - scopelint
# - gochecknoglobals
# - gocognit
# - godot
# - godox
# - goerr113
# - interfacer
# - maligned
# - nestif
# - testpackage
# - wsl
run:
# default concurrency is a available CPU number.
# concurrency: 4 # explicitly omit this value to fully utilize available resources.
deadline: 5m
issues-exit-code: 1
tests: false
# output configuration options
output:
format: "colored-line-number"
print-issued-lines: true
print-linter-name: true
uniq-by-line: true
issues:
# Fix found issues (if it's supported by the linter)
fix: true
exclude-use-default: false
exclude:
- "Error return value of .((os.)?std(out|err)..*|.*Close|.*Flush|os.Remove(All)?|.*print(f|ln)?|os.(Un)?Setenv). is not check"

91
.goreleaser.yml Normal file
View File

@ -0,0 +1,91 @@
env:
- GO111MODULE=on
before:
hooks:
- go mod tidy
builds:
- id: nowin
env:
- CGO_ENABLED=0
- GO111MODULE=on
goos:
- linux
# - darwin
goarch:
- 386
- amd64
# - arm
# - arm64
# goarm:
# - 7
# ignore:
# - goos: darwin
# goarch: arm
# - goos: darwin
# goarch: 386
mod_timestamp: "{{ .CommitTimestamp }}"
flags:
- -trimpath
ldflags:
- -s -w -X main.VERSION=v{{.Version}}
- id: win
env:
- CGO_ENABLED=0
- GO111MODULE=on
goos:
- windows
goarch:
- 386
- amd64
# - arm
goarm:
- 7
mod_timestamp: "{{ .CommitTimestamp }}"
flags:
- -trimpath
ldflags:
- -s -w -X main.VERSION=v{{.Version}}
checksum:
name_template: "{{ .ProjectName }}_checksums.txt"
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
- fix typo
- Merge pull request
- Merge branch
- Merge remote-tracking
- go mod tidy
archives:
- id: binary
builds:
- win
- nowin
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
format_overrides:
- goos: windows
format: binary
- goos: linux
format: binary
- id: nowin
builds:
- nowin
- win
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
format_overrides:
- goos: windows
format: zip
nfpms:
- license: AGPL 3.0
homepage: https://github.com/huoxue1/study_xxqg
file_name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
formats:
- deb
- rpm
maintainer: HuoXue1

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

1
.idea/.name Normal file
View File

@ -0,0 +1 @@
study_xxqg

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/study_xxqg.iml" filepath="$PROJECT_DIR$/.idea/study_xxqg.iml" />
</modules>
</component>
</project>

9
.idea/study_xxqg.iml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

16
README.md Normal file
View File

@ -0,0 +1,16 @@
### 学习强国自动化学习
## 使用
+ 从release下载对应版本压缩包
+ 首次打开会在 ```config\config.yml```生成默认配置文件
+ 再次打开即可运行
## 申明,该项目仅用于学习。
## 鸣谢
+ ### [imkenf/XueQG](https://github.com/imkenf/XueQG)

5
config/config.yml Normal file
View File

@ -0,0 +1,5 @@
# 刷课模式默认为1
# 1只刷文章何视频
# 2只刷文章和视频和每日答题
# 3刷文章和视频和每日答题每周答题和专项答题
model: 1

1
config/user.json Normal file
View File

@ -0,0 +1 @@
[{"cookies":[{"name":"_uab_collina","value":"163662103329486079242507","domain":"pc.xuexi.cn","path":"/points","expires":1951981033,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"__UID__","value":"5cdc19a0-42cd-11ec-b6bc-e3c5195d165e","domain":".xuexi.cn","path":"/","expires":1668157033,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"tmzw","value":"1636621034119","domain":".xuexi.cn","path":"/","expires":1636707434,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"zwfigprt","value":"297bce38be89bc8a076e6e29b6282c1c","domain":".xuexi.cn","path":"/","expires":1636707434,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"003c420ac17482ba6ad5550439dfb427add3b6076673bc476f0beeb76d7abdf6","domain":"pc-api.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10416366210318943764e7c9b024dcd55ba787fb0c5064287171f5d3d","domain":"pc-api.xuexi.cn","path":"/","expires":1636622834,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"171ba83785f1d8fb9d76af9bbb376840828ef4710300b5854145bf5e7fec3c1f","domain":"login.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10416366210325768127e7c9adce9f228d7e2f62ece3cd09618ee90d6","domain":"login.xuexi.cn","path":"/","expires":1636622835,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"nhkb8v0kuyzpFzw6Xptyftdj3b03","domain":"login.xuexi.cn","path":"/","expires":1652173035,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"bhkFmvUOuw7p1swt3pe4kCdf22g3","domain":"www.xuexi.cn","path":"/","expires":1652173036,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"94k6yvb2u6apejwFCpekkm5u6e79","domain":"pc.xuexi.cn","path":"/","expires":1652173036,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"token","value":"143ed9a00afe4c1fbcf1eae8acfdeca3","domain":".xuexi.cn","path":"/","expires":1636642691,"httpOnly":false,"secure":false,"same_site":"None"}],"nick":"苟江山","uid":"151142372517"}]

41
go.mod Normal file
View File

@ -0,0 +1,41 @@
module github.com/huoxue1/study_xxqg
go 1.17
replace github.com/willf/bitset v1.2.1 => github.com/bits-and-blooms/bitset v1.2.1
require (
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
github.com/guonaihong/gout v0.2.9
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
github.com/mxschmitt/playwright-go v0.1100.0
github.com/sirupsen/logrus v1.8.1
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816
github.com/tidwall/gjson v1.11.0
github.com/tuotoo/qrcode v0.0.0-20190222102259-ac9c44189bf2
gopkg.in/yaml.v2 v2.2.8
)
require (
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/google/uuid v1.1.1 // indirect
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/lestrrat-go/strftime v1.0.5 // indirect
github.com/maruel/rs v0.0.0-20150922171536-2c81c4312fe4 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/willf/bitset v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
)

123
go.sum Normal file
View File

@ -0,0 +1,123 @@
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f h1:2dk3eOnYllh+wUOuDhOoC2vUVoJF/5z478ryJ+wzEII=
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk=
github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY=
github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU=
github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/guonaihong/gout v0.2.9 h1:8nU5hrtwP1qDwiadFvU+D+z3ud9WEk8iPSfxQDiebng=
github.com/guonaihong/gout v0.2.9/go.mod h1:H1JqEuZmK4h/urWUq/LnIOEzS1kxl5rK3NkFqZ6Rn48=
github.com/h2non/filetype v1.1.0/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
github.com/lestrrat-go/strftime v1.0.5 h1:A7H3tT8DhTz8u65w+JRpiBxM4dINQhUXAZnhBa2xeOE=
github.com/lestrrat-go/strftime v1.0.5/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g=
github.com/maruel/rs v0.0.0-20150922171536-2c81c4312fe4 h1:u9jwvcKbQpghIXgNl/EOL8hzhAFXh4ePrEP493W3tNA=
github.com/maruel/rs v0.0.0-20150922171536-2c81c4312fe4/go.mod h1:kcRFpEzolcEklV6rD7W95mG49/sbdX/PlFmd7ni3RvA=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mxschmitt/playwright-go v0.1100.0 h1:GkI1TuXU50GlA988VqqdoTObLzi2bbeT8RmLtcxKQrc=
github.com/mxschmitt/playwright-go v0.1100.0/go.mod h1:a3SD3v+56XMA0sDDxXJXy+QGnCfXrNZ/+4gwR5ioSgU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 h1:J6v8awz+me+xeb/cUTotKgceAYouhIB3pjzgRd6IlGk=
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA=
github.com/tidwall/gjson v1.11.0 h1:C16pk7tQNiH6VlCrtIXL1w8GaOsi1X3W8KDkE1BuYd4=
github.com/tidwall/gjson v1.11.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tuotoo/qrcode v0.0.0-20190222102259-ac9c44189bf2 h1:BWVtt2VBY+lmVDu9MGKqLGKl04B+iRHcrW1Ptyi/8tg=
github.com/tuotoo/qrcode v0.0.0-20190222102259-ac9c44189bf2/go.mod h1:lPnW9HVS0vJdeYyQtOvIvlXgZPNhUAhwz+z5r8AJk0Y=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

44
lib/config.go Normal file
View File

@ -0,0 +1,44 @@
package lib
import (
_ "embed"
"os"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
)
type Config struct {
Model int `json:"model" yaml:"model"`
LogLevel string `json:"log_level" yaml:"log_level"`
ShowBrowser bool `json:"show_browser" yaml:"show_browser"`
}
var (
config = Config{
Model: 1,
}
)
//go:embed config_default.yml
var defaultConfig []byte
func GetConfig() Config {
file, err := os.ReadFile("./config/config.yml")
if err != nil {
log.Warningln("检测到配置文件可能不存在")
err := os.WriteFile("./config/config.yml", defaultConfig, 0666)
if err != nil {
log.Errorln("写入到配置文件出现错误")
return Config{}
}
log.Infoln("成功写入到配置文件,请重启应用")
os.Exit(3)
}
err = yaml.Unmarshal(file, &config)
if err != nil {
log.Errorln(err.Error())
return Config{}
}
return config
}

18
lib/config_default.yml Normal file
View File

@ -0,0 +1,18 @@
# 刷课模式默认为1
# 1只刷文章何视频
# 2只刷文章和视频和每日答题
# 3刷文章和视频和每日答题每周答题和专项答题
model: 1
# 日志等级
# panic
# fatal
# error
# warn, warning
# info
# debug
# trace
log_level: "info"
# 是否显示浏览器
show_browser: true

227
lib/core.go Normal file
View File

@ -0,0 +1,227 @@
package lib
import (
"bytes"
"encoding/base64"
"fmt"
"os"
"strings"
qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go"
"github.com/guonaihong/gout"
"github.com/mxschmitt/playwright-go"
log "github.com/sirupsen/logrus"
"github.com/tuotoo/qrcode"
)
type Core struct {
pw *playwright.Playwright
browser playwright.Browser
context playwright.BrowserContext
}
type cookie struct {
Name string `json:"name" yaml:"name"`
Value string `json:"value" yaml:"value"`
Domain string `json:"domain" yaml:"domain"`
Path string `json:"path" yaml:"path"`
Expires int `json:"expires" yaml:"expires"`
HTTPOnly bool `json:"httpOnly" yaml:"http_only"`
Secure bool `json:"secure" yaml:"secure"`
SameSite string `json:"same_site" yaml:"same_site"`
}
func (c *Core) Init() {
pwt, err := playwright.Run()
if err != nil {
log.Errorln("[core]", "初始化playwright失败")
log.Errorln("[core] ", err.Error())
return
}
c.pw = pwt
browser, err := pwt.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
Args: []string{
"--disable-extensions",
"--disable-gpu",
"--no-sandbox",
"--window-size=540,400",
"--start-maximized",
"--mute-audio",
"--window-position=0,0",
"--ignore-certificate-errors",
"--ignore-ssl-errors",
"--disable-features=RendererCodeIntegrity",
"--disable-blink-features",
"--disable-blink-features=AutomationControlled",
},
Channel: nil,
ChromiumSandbox: nil,
Devtools: nil,
DownloadsPath: nil,
ExecutablePath: nil,
HandleSIGHUP: nil,
HandleSIGINT: nil,
HandleSIGTERM: nil,
Headless: playwright.Bool(false),
Proxy: nil,
SlowMo: nil,
Timeout: nil,
})
if err != nil {
log.Errorln("[core] ", "初始化chrome失败")
log.Errorln("[core] ", err.Error())
return
}
c.browser = browser
context, err := c.browser.NewContext()
if err != nil {
return
}
c.context = context
}
func (c *Core) Quit() {
err := c.context.Close()
if err != nil {
return
}
err = c.browser.Close()
if err != nil {
return
}
err = c.pw.Stop()
if err != nil {
return
}
}
func (c *Core) Login() ([]cookie, error) {
page, err := c.context.NewPage()
if err != nil {
return nil, err
}
_, err = page.Goto("https://pc.xuexi.cn/points/login.html", playwright.PageGotoOptions{
Referer: nil,
Timeout: playwright.Float(30000),
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
})
if err != nil {
log.Errorln("[core] ", "打开登录页面失败")
log.Errorln("[core] ", err.Error())
return nil, err
}
log.Infoln("[core] ", "正在等待二维码扫描")
_, _ = page.WaitForSelector(`#app > div > div.login_content > div > div.login_qrcode `)
_, err = page.Evaluate(`let h = document.body.scrollWidth/2;document.documentElement.scrollTop=h;`)
if err != nil {
fmt.Println(err.Error())
return nil, err
}
log.Infoln("[core] ", "加载验证码中,请耐心等待")
frame := page.Frame(playwright.PageFrameOptions{
Name: playwright.String(`ddlogin-iframe`),
URL: nil,
})
if frame == nil {
log.Errorln("获取frame失败")
}
selector, err := frame.QuerySelector(`img`)
if err != nil {
log.Errorln(err.Error())
return nil, err
}
img, err := selector.GetAttribute(`src`)
if err != nil {
log.Errorln(err.Error())
return nil, err
}
img = strings.ReplaceAll(img, "data:image/png;base64,", "")
go sendToQQ(img)
data, err := base64.StdEncoding.DecodeString(img)
if err != nil {
return nil, err
}
os.WriteFile("qrcode.png", data, 0666)
matrix, err := qrcode.Decode(bytes.NewReader(data))
if err != nil {
return nil, err
}
qrcodeTerminal.New().Get(matrix.Content).Print()
_, err = page.WaitForNavigation(playwright.PageWaitForNavigationOptions{
Timeout: playwright.Float(30 * 1000 * 5),
URL: nil,
WaitUntil: nil,
})
if err != nil {
log.Errorln(err.Error())
return nil, err
}
cookies, err := c.context.Cookies() //nolint:wsl
if err != nil {
log.Errorln("[core] ", "获取cookie失败")
return nil, err
}
var (
cos []cookie
)
for _, c := range cookies {
co := cookie{}
co.Name = c.Name
co.Path = c.Path
co.Value = c.Value
co.Domain = c.Domain
co.Expires = c.Expires
co.HTTPOnly = c.HttpOnly
co.SameSite = c.SameSite
co.Secure = c.Secure
cos = append(cos, co)
}
info, nick, err := GetUserInfo(cos)
if err != nil {
return nil, err
}
err = SaveUser(User{
Cookies: cos,
Nick: nick,
Uid: info,
})
if err != nil {
return nil, err
}
return cos, err
}
func sendToQQ(img string) {
err := gout.POST("http://127.0.0.1:5700/send_private_msg").SetJSON(map[string]interface{}{
"user_id": 3343780376,
"message": map[string]interface{}{
"type": "image",
"data": map[string]interface{}{
"file": "base64://" + img,
},
},
}).Do()
if err != nil {
return
}
}

20
lib/core_test.go Normal file
View File

@ -0,0 +1,20 @@
package lib
import (
"fmt"
"testing"
)
func TestName(t *testing.T) {
core := Core{}
core.Init()
cookies, err := core.Login()
if err != nil {
return
}
score, err := GetUserScore(cookies)
if err != nil {
return
}
fmt.Println(score)
}

489
lib/respond.go Normal file
View File

@ -0,0 +1,489 @@
package lib
import (
rand2 "math/rand"
"regexp"
"strings"
"time"
"github.com/mxschmitt/playwright-go"
log "github.com/sirupsen/logrus"
)
const (
MyPointsUri = "https://pc.xuexi.cn/points/my-points.html"
DailyBUTTON = `#app > div > div.layout-body > div >
div.my-points-section > div.my-points-content > div:nth-child(5) > div.my-points-card-footer > div.buttonbox > div`
WEEKEND = `#app > div > div.layout-body >
div > div.my-points-section > div.my-points-content > div:nth-child(6) > div.my-points-card-footer > div.buttonbox > div`
SPECIALBUTTON = `#app > div > div.layout-body >
div > div.my-points-section > div.my-points-content > div:nth-child(7) > div.my-points-card-footer > div.buttonbox > div`
)
func (c *Core) RespondDaily(cookies []cookie, model string) {
defer func() {
err := recover()
if err != nil {
log.Errorln("答题模块异常结束")
}
}()
// 获取用户成绩
score, err := GetUserScore(cookies)
if err != nil {
log.Errorln("获取分数失败,停止每日答题", err.Error())
return
}
page, err := c.context.NewPage()
if err != nil {
log.Errorln("创建页面失败" + err.Error())
return
}
err = c.context.AddCookies(cookieToParam(cookies)...)
if err != nil {
log.Errorln("添加cookie信息失败已退出答题")
return
}
log.Infoln("已加载每日答题模块")
_, err = page.Goto(MyPointsUri, playwright.PageGotoOptions{
Referer: playwright.String(MyPointsUri),
Timeout: playwright.Float(1000),
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
})
if err != nil {
log.Errorln("跳转页面失败")
return
}
switch model {
case "daily":
{
// 检测是否已经完成
if score.Content["daily"].CurrentScore >= score.Content["daily"].MaxScore {
log.Infoln("检测到每日答题已经完成,即将退出答题")
return
}
err = page.Click(DailyBUTTON)
if err != nil {
log.Errorln("跳转到积分页面错误")
return
}
}
case "weekly":
{
// 检测是否已经完成
if score.Content["weekly"].CurrentScore >= score.Content["weekly"].MaxScore {
log.Infoln("检测到每周答题已经完成,即将退出答题")
return
}
err = page.Click(WEEKEND)
if err != nil {
log.Errorln("跳转到积分页面错误")
return
}
}
case "special":
{
// 检测是否已经完成
if score.Content["special"].CurrentScore >= score.Content["special"].MaxScore {
log.Infoln("检测到特殊答题已经完成,即将退出答题")
return
}
err = page.Click(SPECIALBUTTON)
if err != nil {
log.Errorln("跳转到积分页面错误")
return
}
}
}
time.Sleep(5 * time.Second)
getAnswerPage(page, model)
for true {
// 查看是否存在答题按钮,若按钮可用则重新提交答题
btn, err := page.QuerySelector(`#app > div > div.layout-body > div > div.detail-body > div.action-row > button`)
if err != nil {
log.Infoln("获取提交按钮失败,本次答题结束" + err.Error())
return
}
enabled, err := btn.IsEnabled()
if err != nil {
log.Errorln(err.Error())
continue
}
if enabled {
log.Infoln("检测到有答案未提交,将重新提交")
err := btn.Click()
if err != nil {
log.Errorln("提交答案失败")
}
}
switch model {
case "daily":
{
// 检测是否已经完成
if score.Content["daily"].CurrentScore >= score.Content["daily"].MaxScore {
log.Infoln("检测到每日答题已经完成,即将退出答题")
return
}
}
case "weekly":
{
// 检测是否已经完成
if score.Content["weekly"].CurrentScore >= score.Content["weekly"].MaxScore {
log.Infoln("检测到每周答题已经完成,即将退出答题")
return
}
}
case "special":
{
// 检测是否已经完成
if score.Content["special"].CurrentScore >= score.Content["special"].MaxScore {
log.Infoln("检测到特殊答题已经完成,即将退出答题")
return
}
}
}
// 获取题目类型
category, err := page.QuerySelector(
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-header`)
if err != nil {
log.Errorln("没有找到题目元素" + err.Error())
return
}
time.Sleep(1 * time.Second)
// 获取题目
question, err := page.QuerySelector(
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-body > div`)
if err != nil {
log.Errorln("未找到题目问题元素")
return
}
categoryText, err := category.TextContent()
if err != nil {
log.Errorln("获取题目元素失败" + err.Error())
return
}
log.Infoln("## 题目类型:" + categoryText)
questionText, err := question.TextContent()
if err != nil {
log.Errorln("获取题目问题失败" + err.Error())
return
}
log.Infoln("## 题目:" + questionText)
// 获取答题帮助
openTips, err := page.QuerySelector(
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-footer > span`)
if err != nil {
log.Errorln("为获取到题目提示信息" + err.Error())
return
}
err = openTips.Click()
if err != nil {
log.Errorln("点击打开提示信息按钮失败" + err.Error())
return
}
content, err := page.Content()
if err != nil {
log.Errorln("获取网页全体内容失败" + err.Error())
return
}
err = openTips.Click()
if err != nil {
log.Errorln("点击打开提示信息按钮失败" + err.Error())
return
}
tips := getTips(content)
log.Infoln("[提示信息]", tips)
// 填空题
switch {
case strings.Contains(categoryText, "填空题"):
err := FillBlank(page, tips)
if err != nil {
log.Errorln("填空题答题失败" + err.Error())
return
}
case strings.Contains(categoryText, "多选题"):
log.Infoln("读取到多选题")
options, err := getOptions(page)
if err != nil {
log.Errorln("获取选项失败" + err.Error())
return
}
log.Infoln("获取到选项答案:", options)
log.Infoln("[多选题选项]", options)
var answer []string
for _, option := range options {
for _, tip := range tips {
if strings.Contains(option, tip) {
answer = append(answer, option)
}
}
}
err = radioCheck(page, answer)
if err != nil {
return
}
case strings.Contains(categoryText, "单选题"):
log.Infoln("读取到单选题")
options, err := getOptions(page)
if err != nil {
log.Errorln("获取选项失败" + err.Error())
return
}
log.Infoln("获取到选项答案:", options)
log.Infoln("[多选题选项]", options)
var answer []string
for _, option := range options {
for _, tip := range tips {
if strings.Contains(option, tip) {
answer = append(answer, option)
}
}
}
err = radioCheck(page, answer)
if err != nil {
return
}
}
score, _ = GetUserScore(cookies)
}
}
func getAnswerPage(page playwright.Page, model string) {
selectPages, err := page.QuerySelectorAll(`#app .ant-pagination .ant-pagination-item`)
if err != nil {
log.Errorln("获取到页码失败")
return
}
log.Infoln("共获取到", len(selectPages), "页")
modelName := ""
modelSlector := ""
switch model {
case "daily":
return
case "weekly":
modelName = "每周答题"
modelSlector = "button.ant-btn-primary"
case "special":
modelName = "专项答题"
modelSlector = "#app .items .item button"
}
for i := 1; i <= len(selectPages); i++ {
log.Infoln("获取到"+modelName, "第", i, "页")
err1 := selectPages[i-1].Click()
if err1 != nil {
log.Errorln("点击页码失败")
}
datas, err := page.QuerySelectorAll(modelSlector)
if err != nil {
log.Errorln("获取页面内容失败")
continue
}
for _, data := range datas {
time.Sleep(3 * time.Second)
content, err := data.TextContent()
if err != nil {
continue
}
if strings.Contains(content, "重新") || strings.Contains(content, "满分") {
continue
} else {
if strings.Contains(content, "电影试题") {
log.Infoln("发现有未答题的电影试题")
continue
}
enabled, err := data.IsEnabled()
if err != nil {
return
}
if enabled {
log.Infoln("按钮可用")
}
err = data.Click(playwright.ElementHandleClickOptions{
Button: nil,
ClickCount: playwright.Int(2),
Delay: nil,
Force: nil,
Modifiers: nil,
NoWaitAfter: nil,
Position: nil,
Timeout: playwright.Float(100000),
})
if err != nil {
log.Errorln("点击按钮失败" + err.Error())
time.Sleep(2 * time.Second)
continue
}
time.Sleep(3 * time.Second)
return
}
}
}
}
func radioCheck(page playwright.Page, answer []string) error {
radios, err := page.QuerySelectorAll(`.q-answer.choosable`)
if err != nil {
log.Errorln("获取选项失败")
return err
}
log.Debugln("获取到", len(radios), "个按钮")
for _, radio := range radios {
textContent, err := radio.TextContent()
if err != nil {
return err
}
for _, s := range answer {
if textContent == s {
err := radio.Click()
if err != nil {
return err
}
r := rand2.Intn(2)
time.Sleep(time.Duration(r) * time.Second)
}
}
}
r := rand2.Intn(5)
time.Sleep(time.Duration(r) * time.Second)
checkNextBotton(page)
return nil
}
func getOptions(page playwright.Page) ([]string, error) {
handles, err := page.QuerySelectorAll(`.q-answer.choosable`)
if err != nil {
log.Errorln("获取选项信息失败")
return nil, err
}
var options []string
for _, handle := range handles {
content, err := handle.TextContent()
if err != nil {
return nil, err
}
options = append(options, content)
}
return options, err
}
func getTips(data string) []string {
data = strings.ReplaceAll(data, " ", "")
data = strings.ReplaceAll(data, "\n", "")
compile := regexp.MustCompile(`<fontcolor="red">(.*?)</font>`)
match := compile.FindAllStringSubmatch(data, -1)
var tips []string
for _, i := range match {
tips = append(tips, i[1])
}
return tips
}
func FillBlank(page playwright.Page, tips []string) error {
video := false
var answer []string
for _, tip := range tips {
if tip == "请观看视频" {
video = true
}
}
if video {
answer = append(answer, "不知道")
} else {
answer = tips
}
inouts, err := page.QuerySelectorAll(`div.q-body > div > input`)
if err != nil {
log.Errorln("获取输入框错误" + err.Error())
return err
}
log.Debugln("获取到", len(inouts), "个填空")
if len(inouts) == 1 && len(tips) > 1 {
temp := ""
for _, tip := range tips {
temp += tip
}
answer = strings.Split(temp, ",")
log.Infoln("答案已合并处理" + err.Error())
}
for i := 0; i < len(inouts); i++ {
err := inouts[i].Fill(answer[i])
if err != nil {
log.Errorln("填充答案失败" + err.Error())
continue
}
r := rand2.Intn(5)
time.Sleep(time.Duration(r) * time.Second)
}
r := rand2.Intn(2)
time.Sleep(time.Duration(r) * time.Second)
checkNextBotton(page)
return nil
}
func checkNextBotton(page playwright.Page) {
btns, err := page.QuerySelectorAll(`#app .action-row > button`)
if err != nil {
log.Errorln("未检测到按钮" + err.Error())
return
}
if len(btns) <= 1 {
err := btns[0].Check()
if err != nil {
log.Errorln("点击吓一题按钮失败")
return
}
time.Sleep(2 * time.Second)
_, err = btns[0].GetAttribute("disabled")
if err != nil {
log.Infoln("未检测到禁言属性")
return
}
} else {
err := btns[1].Click()
if err != nil {
log.Errorln("提交试卷失败")
return
}
log.Infoln("已成功提交试卷")
}
}

98
lib/score.go Normal file
View File

@ -0,0 +1,98 @@
package lib
import (
"fmt"
"github.com/guonaihong/gout"
log "github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
)
type Score struct {
TotalScore int
TodayScore int
Content map[string]Data
}
type Data struct {
CurrentScore int
MaxScore int
}
func GetUserScore(cookies []cookie) (Score, error) {
var score Score
var resp []byte
// 获取用户总分
err := gout.GET(user_totalScore_url).SetCookies(cookieToJar(cookies)...).SetHeader(gout.H{
"Cache-Control": "no-cache",
}).BindBody(&resp).Do()
if err != nil {
log.Errorln("获取用户总分错误" + err.Error())
return Score{}, err
}
log.Debugln(gjson.GetBytes(resp, "@this|@pretty"))
score.TotalScore = int(gjson.GetBytes(resp, "data.score").Int())
// 获取用户今日得分
err = gout.GET(user_todayTotalScore_url).SetCookies(cookieToJar(cookies)...).SetHeader(gout.H{
"Cache-Control": "no-cache",
}).BindBody(&resp).Do()
if err != nil {
log.Errorln("获取用户每日总分错误" + err.Error())
return Score{}, err
}
log.Debugln(gjson.GetBytes(resp, "@this|@pretty"))
score.TodayScore = int(gjson.GetBytes(resp, "data.score").Int())
err = gout.GET(user_rateScore_url).SetCookies(cookieToJar(cookies)...).SetHeader(gout.H{
"Cache-Control": "no-cache",
}).BindBody(&resp).Do()
if err != nil {
log.Errorln("获取用户积分出现错误" + err.Error())
return Score{}, err
}
log.Debugln(gjson.GetBytes(resp, "@this|@pretty"))
datas := gjson.GetBytes(resp, "data.taskProgress").Array()
m := make(map[string]Data, 7)
m["article"] = Data{
CurrentScore: int(datas[0].Get("currentScore").Int()),
MaxScore: int(datas[0].Get("dayMaxScore").Int()),
}
m["video"] = Data{
CurrentScore: int(datas[1].Get("currentScore").Int()),
MaxScore: int(datas[1].Get("dayMaxScore").Int()),
}
m["weekly"] = Data{
CurrentScore: int(datas[2].Get("currentScore").Int()),
MaxScore: int(datas[2].Get("dayMaxScore").Int()),
}
m["video_time"] = Data{
CurrentScore: int(datas[3].Get("currentScore").Int()),
MaxScore: int(datas[3].Get("dayMaxScore").Int()),
}
m["login"] = Data{
CurrentScore: int(datas[4].Get("currentScore").Int()),
MaxScore: int(datas[4].Get("dayMaxScore").Int()),
}
m["special"] = Data{
CurrentScore: int(datas[5].Get("currentScore").Int()),
MaxScore: int(datas[5].Get("dayMaxScore").Int()),
}
m["daily"] = Data{
CurrentScore: int(datas[6].Get("currentScore").Int()),
MaxScore: int(datas[6].Get("dayMaxScore").Int()),
}
score.Content = m
return score, err
}
func PrintScore(score Score) {
log.Infoln(fmt.Sprintf("当前学习总积分:%d 今日得分:%d", score.TodayScore, score.TodayScore))
for s, data := range score.Content {
log.Infoln(s, ": ", data.CurrentScore, "/", data.MaxScore)
}
}

252
lib/study.go Normal file
View File

@ -0,0 +1,252 @@
package lib
import (
"encoding/json"
"errors"
"fmt"
"math/rand"
"strconv"
"time"
"github.com/guonaihong/gout"
"github.com/mxschmitt/playwright-go"
log "github.com/sirupsen/logrus"
)
var (
article_url_list = []string{
"https://www.xuexi.cn/lgdata/35il6fpn0ohq.json",
"https://www.xuexi.cn/lgdata/45a3hac2bf1j.json",
"https://www.xuexi.cn/lgdata/1ajhkle8l72.json",
"https://www.xuexi.cn/lgdata/1ahjpjgb4n3.json",
"https://www.xuexi.cn/lgdata/1je1objnh73.json",
"https://www.xuexi.cn/lgdata/1kvrj9vvv73.json",
"https://www.xuexi.cn/lgdata/17qonfb74n3.json",
"https://www.xuexi.cn/lgdata/1i30sdhg0n3.json"}
video_url_list = []string{
"https://www.xuexi.cn/lgdata/3j2u3cttsii9.json",
"https://www.xuexi.cn/lgdata/1novbsbi47k.json",
"https://www.xuexi.cn/lgdata/31c9ca1tgfqb.json",
"https://www.xuexi.cn/lgdata/1oajo2vt47l.json",
"https://www.xuexi.cn/lgdata/18rkaul9h7l.json",
"https://www.xuexi.cn/lgdata/2qfjjjrprmdh.json",
"https://www.xuexi.cn/lgdata/3o3ufqgl8rsn.json",
"https://www.xuexi.cn/lgdata/525pi8vcj24p.json",
"https://www.xuexi.cn/lgdata/1742g60067k.json"}
)
type Link struct {
Editor string `json:"editor"`
PublishTime string `json:"publishTime"`
ItemType string `json:"itemType"`
Author string `json:"author"`
CrossTime int `json:"crossTime"`
Source string `json:"source"`
NameB string `json:"nameB"`
Title string `json:"title"`
Type string `json:"type"`
Url string `json:"url"`
ShowSource string `json:"showSource"`
ItemId string `json:"itemId"`
ThumbImage string `json:"thumbImage"`
AuditTime string `json:"auditTime"`
ChannelNames []string `json:"channelNames"`
Producer string `json:"producer"`
ChannelIds []string `json:"channelIds"`
DataValid bool `json:"dataValid"`
}
func getLinks(model string) ([]Link, error) {
UID := rand.Intn(20000000) + 10000000
learnUrl := ""
if model == "article" {
learnUrl = article_url_list[rand.Intn(7)]
} else if model == "video" {
learnUrl = video_url_list[rand.Intn(7)]
} else {
return nil, errors.New("model选择出现错误")
}
var (
resp []byte
)
err := gout.GET(learnUrl + "?_st=" + strconv.Itoa(UID)).BindBody(&resp).Do()
if err != nil {
log.Errorln("请求连接列表出现错误" + err.Error())
return nil, err
}
var links []Link
err = json.Unmarshal(resp, &links)
if err != nil {
log.Errorln("解析列表出现错误" + err.Error())
return nil, err
}
return links, err
}
func (c *Core) LearnArticle(cookies []cookie) {
defer func() {
err := recover()
if err != nil {
log.Errorln("文章学习模块异常结束")
}
}()
score, err := GetUserScore(cookies)
if err != nil {
log.Errorln(err.Error())
return
}
links, _ := getLinks("article")
if score.Content["article"].CurrentScore < score.Content["article"].MaxScore {
log.Infoln("开始加载文章学习模块")
page, err := c.context.NewPage()
if err != nil {
return
}
err = c.context.AddCookies(cookieToParam(cookies)...)
if err != nil {
log.Errorln("添加cookie失败" + err.Error())
return
}
tryCount := 0
for {
if tryCount < 20 {
PrintScore(score)
n := rand.Intn(len(links))
_, err := page.Goto(links[n].Url, playwright.PageGotoOptions{
Referer: playwright.String(links[rand.Intn(len(links))].Url),
Timeout: playwright.Float(10000),
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
})
if err != nil {
log.Errorln("页面跳转失败")
}
log.Infoln("正在学习文章:" + links[n].Title)
log.Infoln("文章发布时间:" + links[n].PublishTime)
log.Infoln("文章学习链接:" + links[n].Url)
learnTime := 50 + rand.Intn(5) + 10
log.Infoln(fmt.Sprintf("正在进行阅读学习中,剩余%d篇本篇剩余时间%d秒", score.Content["article"].MaxScore-score.Content["article"].CurrentScore, learnTime))
for i := 0; i < learnTime; i++ {
if rand.Float32() > 0.5 {
go func() {
_, err = page.Evaluate(fmt.Sprintf(`let h = document.body.scrollHeight/120*%d;document.documentElement.scrollTop=h;`, i))
if err != nil {
log.Errorln("文章滑动失败")
}
}()
}
time.Sleep(1 * time.Second)
}
if score.Content["article"].CurrentScore >= score.Content["article"].MaxScore {
log.Infoln("检测到本次阅读学习分数已满,退出学习")
break
}
score, _ = GetUserScore(cookies)
tryCount++
} else {
log.Errorln("阅读学习出现异常,稍后可重新学习")
}
}
} else {
log.Infoln("检测到文章学习已经完成")
}
}
func (c *Core) LearnVideo(cookies []cookie) {
defer func() {
err := recover()
if err != nil {
log.Errorln("视频学习模块异常结束")
}
}()
score, err := GetUserScore(cookies)
if err != nil {
log.Errorln(err.Error())
return
}
links, _ := getLinks("video")
if score.Content["video"].CurrentScore < score.Content["video"].MaxScore || score.Content["video_time"].CurrentScore < score.Content["video_time"].MaxScore {
log.Infoln("开始加载视频学习模块")
// core := Core{}
//core.Init()
page, err := c.context.NewPage()
if err != nil {
return
}
var resp string
err = gout.GET("http://1.15.144.22/stealth.min.js").BindBody(&resp).Do()
if err != nil {
return
}
err = page.AddInitScript(playwright.PageAddInitScriptOptions{
Script: playwright.String(resp),
Path: nil,
})
if err != nil {
return
}
err = c.context.AddCookies(cookieToParam(cookies)...)
if err != nil {
log.Errorln("添加cookie失败" + err.Error())
return
}
tryCount := 0
networkCookies, err := c.context.Cookies()
if err != nil {
return
}
for _, networkCookie := range networkCookies {
fmt.Println(networkCookie.Name)
}
for {
if tryCount < 20 {
PrintScore(score)
n := rand.Intn(len(links))
_, err := page.Goto(links[n].Url, playwright.PageGotoOptions{
Referer: playwright.String(links[rand.Intn(len(links))].Url),
Timeout: playwright.Float(10000),
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
})
if err != nil {
log.Errorln("页面跳转失败")
}
log.Infoln("正在观看视频:" + links[n].Title)
log.Infoln("视频发布时间:" + links[n].PublishTime)
log.Infoln("视频学习链接:" + links[n].Url)
learnTime := 50 + rand.Intn(5) + 10
log.Infoln(fmt.Sprintf("正在进行视频学习中,剩余%d个当前剩余时间%d秒", score.Content["video"].MaxScore-score.Content["video"].CurrentScore, learnTime))
for i := 0; i < learnTime; i++ {
if rand.Float32() > 0.5 {
go func() {
_, err := page.Evaluate(fmt.Sprintf(`let h = document.body.scrollHeight/120*%d;document.documentElement.scrollTop=h;`, i))
if err != nil {
log.Errorln("视频滑动失败")
}
}()
}
time.Sleep(1 * time.Second)
}
if score.Content["video"].CurrentScore >= score.Content["video"].MaxScore || score.Content["video_time"].CurrentScore >= score.Content["video_time"].MaxScore {
log.Infoln("检测到本次视频学习分数已满,退出学习")
break
}
score, _ = GetUserScore(cookies)
tryCount++
} else {
log.Errorln("视频学习出现异常,稍后可重新学习")
}
}
} else {
log.Infoln("检测到视频学习已经完成")
}
}

9
lib/study_test.go Normal file
View File

@ -0,0 +1,9 @@
package lib
import (
"testing"
)
func TestName1(t *testing.T) {
CheckUserCookie(User{})
}

8
lib/url.go Normal file
View File

@ -0,0 +1,8 @@
package lib
const (
user_Info_url = "https://pc-api.xuexi.cn/open/api/user/info"
user_totalScore_url = "https://pc-api.xuexi.cn/open/api/score/get"
user_todayTotalScore_url = "https://pc-api.xuexi.cn/open/api/score/today/query"
user_rateScore_url = "https://pc-proxy-api.xuexi.cn/api/score/days/listScoreProgress?sence=score&deviceType=2"
)

117
lib/user.go Normal file
View File

@ -0,0 +1,117 @@
package lib
import (
"encoding/json"
"os"
"github.com/guonaihong/gout"
log "github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
)
func init() {
_, err := os.Stat(`./config/user.json`)
if err != nil {
err := os.WriteFile(user_path, []byte("[]"), 0666)
if err != nil {
return
}
return
}
}
const (
user_path = "./config/user.json"
)
type User struct {
Cookies []cookie `json:"cookies"`
Nick string `json:"nick"`
Uid string `json:"uid"`
}
func GetUsers() ([]User, error) {
file, err := os.ReadFile(user_path)
if err != nil {
return nil, err
}
var users []User
err = json.Unmarshal(file, &users)
if err != nil {
return nil, err
}
var newUsers []User
for i := 0; i < len(users); i++ {
if CheckUserCookie(users[i]) {
newUsers = append(newUsers, users[i])
continue
}
log.Infoln("用户" + users[i].Nick + "cookie已失效")
}
return users, err
}
func SaveUser(user User) error {
users, err := GetUsers()
if err != nil {
log.Errorln("获取用户信息错误")
return err
}
a := false
for _, u := range users {
if u.Uid == user.Uid {
u.Cookies = user.Cookies
a = true
}
}
if !a {
users = append(users, user)
}
data, err := json.Marshal(&users)
if err != nil {
log.Errorln("序列化用户失败")
return err
}
err = os.WriteFile(user_path, data, 0666)
if err != nil {
log.Errorln("写入用户信息到文件错误")
return err
}
return err
}
func GetUserInfo(cookies []cookie) (string, string, error) {
var resp []byte
err := gout.GET(user_Info_url).
SetCookies(cookieToJar(cookies)...).
SetHeader(gout.H{
"Cache-Control": "no-cache",
}).BindBody(&resp).Do()
if err != nil {
log.Errorln("获取用户信息失败")
return "", "", err
}
log.Debugln("[user] 用户信息:", gjson.GetBytes(resp, "@this|@pretty").String())
uid := gjson.GetBytes(resp, "data.uid").String()
nick := gjson.GetBytes(resp, "data.nick").String()
return uid, nick, err
}
func CheckUserCookie(user User) bool {
var resp []byte
err := gout.GET(`https://pc-api.xuexi.cn/open/api/score/get?_t=1636607911602`).SetCookies(cookieToJar(user.Cookies)...).BindBody(&resp).Do()
if err != nil {
log.Errorln(err.Error())
return true
}
if gjson.GetBytes(resp, "code").Int() == 401 && gjson.GetBytes(resp, "message").String() == "token check failed" {
return true
}
return false
}

1
lib/user_test.go Normal file
View File

@ -0,0 +1 @@
package lib

47
lib/utils.go Normal file
View File

@ -0,0 +1,47 @@
package lib
import (
"net/http"
"github.com/mxschmitt/playwright-go"
)
func cookieToJar(cookies []cookie) []*http.Cookie {
var (
cooks []*http.Cookie
)
for _, c := range cookies {
cooks = append(
cooks,
&http.Cookie{
Name: c.Name,
Value: c.Value,
Path: c.Path,
Domain: c.Domain,
Secure: c.Secure,
HttpOnly: c.HTTPOnly,
},
)
}
return cooks
}
func cookieToParam(cookies []cookie) []playwright.SetNetworkCookieParam {
var (
cooks []playwright.SetNetworkCookieParam
)
for _, c := range cookies {
cooks = append(cooks, playwright.SetNetworkCookieParam{
Name: c.Name,
Value: c.Value,
URL: playwright.String(""),
Domain: playwright.String(c.Domain),
Path: playwright.String(c.Path),
Expires: playwright.Int(c.Expires),
HttpOnly: playwright.Bool(c.HTTPOnly),
Secure: playwright.Bool(c.Secure),
SameSite: playwright.String(c.SameSite),
})
}
return cooks
}

BIN
main.exe Normal file

Binary file not shown.

70
main.go Normal file
View File

@ -0,0 +1,70 @@
package main
import (
"os"
"path"
"time"
rotates "github.com/lestrrat-go/file-rotatelogs"
log "github.com/sirupsen/logrus"
easy "github.com/t-tomalak/logrus-easy-formatter"
"github.com/huoxue1/study_xxqg/lib"
)
func init() {
config = lib.GetConfig()
logFormatter := &easy.Formatter{
TimestampFormat: "2006-01-02 15:04:05",
LogFormat: "[%time%] [%lvl%]: %msg% \n",
}
w, err := rotates.New(path.Join("logs", "%Y-%m-%d.log"), rotates.WithRotationTime(time.Hour*24))
if err != nil {
log.Errorf("rotates init err: %v", err)
panic(err)
}
log.SetOutput(w)
log.SetFormatter(logFormatter)
level, err := log.ParseLevel(config.LogLevel)
log.SetLevel(level)
}
var (
config lib.Config
)
func init() {
_, err := os.Stat(`./config/`)
if err != nil {
os.Mkdir("./config/", 0666)
return
}
}
func main() {
log.Infoln(`// 刷课模式默认为1
1只刷文章何视频
2只刷文章和视频和每日答题
3刷文章和视频和每日答题每周答题和专项答题`)
log.Infoln("检测到模式", config.Model)
core := lib.Core{}
defer core.Quit()
core.Init()
login, err := core.Login()
if err != nil {
return
}
core.LearnArticle(login)
core.LearnVideo(login)
if config.Model == 2 {
core.RespondDaily(login, "daily")
} else if config.Model == 3 {
core.RespondDaily(login, "daily")
core.RespondDaily(login, "weekly")
core.RespondDaily(login, "special")
}
}

BIN
qrcode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

1
user.json Normal file
View File

@ -0,0 +1 @@
[{"cookies":[{"name":"_uab_collina","value":"163661069885993287694617","domain":"pc.xuexi.cn","path":"/points","expires":1951970698,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"__UID__","value":"4d0dda30-42b5-11ec-8eab-7b360a497c38","domain":".xuexi.cn","path":"/","expires":1668146699,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"tmzw","value":"1636610699718","domain":".xuexi.cn","path":"/","expires":1636697099,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"zwfigprt","value":"326756256aef95deeac0da98de19540a","domain":".xuexi.cn","path":"/","expires":1636697099,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"3212c84c4db8248eb50cafb336966f583ec86bde33da115a4561f52089443041","domain":"pc-api.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10a16366106974298596e40c8422b249f6358963e35bdec6a06e7fffc","domain":"pc-api.xuexi.cn","path":"/","expires":1636612500,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"e1ca5c9dbc630cf0cd3a4479a7cb7827b29e00e66d27bc969d7ede5f659a28ac","domain":"login.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10a16366106983052977e40cad89c774137b66301bdc7f0766c8365f7","domain":"login.xuexi.cn","path":"/","expires":1636612501,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"q2kIFvUvu68jwgrLg7LXxzt6sp2n","domain":"login.xuexi.cn","path":"/","expires":1652162702,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"qnkIdvOnu16j6LrUR7d9xjnosUR9","domain":"pc.xuexi.cn","path":"/","expires":1652162702,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"y5kOpvmgu6zjFnrqU8Is8atmzI1e","domain":"www.xuexi.cn","path":"/","expires":1652162702,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"token","value":"393807e803174851ac408d5a97ae0d97","domain":".xuexi.cn","path":"/","expires":1636632336,"httpOnly":false,"secure":false,"same_site":"None"}],"nick":"gjs","uid":"151172176463"},{"cookies":[{"name":"_uab_collina","value":"163661377781318630961955","domain":"pc.xuexi.cn","path":"/points","expires":1951973777,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"__UID__","value":"78569db0-42bc-11ec-9199-7dc30372e140","domain":".xuexi.cn","path":"/","expires":1668149778,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"tmzw","value":"1636613778733","domain":".xuexi.cn","path":"/","expires":1636700178,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"zwfigprt","value":"d90dcffd85a58b9228f41a3564b585f9","domain":".xuexi.cn","path":"/","expires":1636700178,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"e73d7582129f14b8e44805900fe16c6b3d1cb98cfbf3e92e2daaf5de778a0041","domain":"pc-api.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10a16366137763874277e40f11af2eb6b2a22101afc55394b828f1b9e","domain":"pc-api.xuexi.cn","path":"/","expires":1636615579,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"edf43c7511240e88c17b406bf729a9ee5fa1c286aab41995912ee012e478d4d6","domain":"login.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10a16366137768314189e40f324b65cd4dd52322d849bd68424a12439","domain":"login.xuexi.cn","path":"/","expires":1636615579,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"tqkLUvkhuFalRsl0d7n7pqw2X2nb","domain":"www.xuexi.cn","path":"/","expires":1652165781,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"U6kIsvCyud8lhglmb8ev1pk5pnak","domain":"login.xuexi.cn","path":"/","expires":1652165781,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"ItkwCv85uFqlyLl038zb1v6nzy2b","domain":"pc.xuexi.cn","path":"/","expires":1652165781,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"token","value":"c18d4e0283514eeda1a4fe6cf63e3ac6","domain":".xuexi.cn","path":"/","expires":1636635418,"httpOnly":false,"secure":false,"same_site":"None"}],"nick":"苟江山","uid":"151142372517"}]