Skip to content

Commit 43eed12

Browse files
committed
make autospider work in incognito mode
use webrequest to get cookie correctly handle login & unlogin state better faking request
1 parent db5d865 commit 43eed12

File tree

12 files changed

+219
-83
lines changed

12 files changed

+219
-83
lines changed

ZhiHuExt/APIPageHooker.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"use strict"
2+
3+
switch(window.location.pathname)
4+
{
5+
case "/autospider":
6+
{
7+
const frame = document.createElement('iframe');
8+
frame.width = "100%";
9+
frame.height = "100%";
10+
frame.src = chrome.extension.getURL('AutoSpider.html');
11+
document.addEventListener("DOMContentLoaded", () =>
12+
{
13+
setTimeout(()=>document.body.appendChild(frame), 1500); // workaround for JSONView
14+
});
15+
frame.onload = ()=>fetch("https://api.zhihu.com/getcookie", { credentials: "include" });
16+
}
17+
break;
18+
}
19+

ZhiHuExt/AutoSpider.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</style>
2424
</head>
2525
<body>
26-
<iframe src="https://api.zhihu.com/getcookie" id="ifr" style="display: none"></iframe>
26+
<!-- <iframe src="https://api.zhihu.com/getcookie" id="ifr" style="display: none"></iframe> -->
2727
<div>
2828
<table id="maintable" class="cell-border hover order-column stripe" width="100%">
2929
<thead>
@@ -45,6 +45,7 @@
4545
<button id="refresh">刷新</button>
4646
<button id="show404">失败项</button>
4747
<button id="del404">清理失败项</button>
48+
<button id="showban">封禁项</button>
4849
<button id="go">开始</button>
4950
<button id="chkban">复查封禁</button>
5051
<br />
@@ -61,10 +62,11 @@
6162
<button id="clean">清理</button>
6263
<button id="export">导出</button>
6364
<button id="import">导入</button> <input type="file" id="infile" />
65+
<button id="bakstate">备份状态</button>
6466
</div>
6567
<div>
6668
<textarea id="userinput" style="width:100%; height:160px"></textarea>
67-
<textarea id="out404" style="width:100%; height:50px"></textarea>
69+
<textarea id="outbox" style="width:100%; height:50px"></textarea>
6870
</div>
6971
</div>
7072
<script src="AutoSpider.js"></script>

ZhiHuExt/AutoSpider.js

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
"use strict"
22

33
/**@type {Map<string, User>}}*/
4-
const uids = new Map();
4+
let uids = new Map();
55
/**@type {Map<string, number>}}*/
6-
const utimeOld = new Map(), utimeNew = new Map();
7-
const u404s = new Set();
6+
let utimeOld = new Map();
7+
/**@type {Map<string, number>}}*/
8+
let utimeNew = new Map();
9+
let u404s = new Set();
810
let chkreports = new StandardDB();
911
let isRunning = false;
1012
let rowcount = 0;
13+
let curBtn = null;
1114

1215
/**@type {HTMLInputElement}}*/
1316
const aloneRec = $("#aloneRec")[0], autoLoop = $("#autoLoop")[0], wtime = $("#waittime")[0], maxact = $("#maxact")[0], limitdate = $("#limitdate")[0];
@@ -57,6 +60,10 @@ async function fastChk(uid, begintime, wailtAll)
5760
{
5861
ContentBase.BASE_LIM_DATE = new Date(limitdate.value).toUTCSeconds();
5962
const user = await ContentBase.checkUserState(uid, bypasser, [maxact.value], wailtAll);
63+
if(curBtn)
64+
{
65+
curBtn.style.background = user ? "green" : "red";
66+
}
6067
if (!user)
6168
{
6269
u404s.add(uid);
@@ -122,7 +129,12 @@ $(document).on("click", "input[name=repeat]:radio", e =>
122129
});
123130
$(document).on("click", "#show404", e =>
124131
{
125-
$("#out404")[0].value = JSON.stringify(u404s.toArray());
132+
$("#outbox")[0].value = JSON.stringify(u404s.toArray());
133+
});
134+
$(document).on("click", "#showban", e =>
135+
{
136+
const bans = Array.from(uids.values()).filter(u=>u.status!="").mapToProp("id");
137+
$("#outbox")[0].value = JSON.stringify(bans);
126138
});
127139
$(document).on("click", "#del404", e =>
128140
{
@@ -136,6 +148,54 @@ $(document).on("click", "#clean", e =>
136148
{
137149
chkreports = new StandardDB();
138150
});
151+
$(document).on("click", "#bakstate", e=>
152+
{
153+
const state =
154+
{
155+
users: Array.from(Array.from(uids.values())),
156+
utimeOld: Array.from(utimeOld.entries()),
157+
utimeNew: Array.from(utimeNew.entries()),
158+
u404s: u404s.toArray(),
159+
chkreports: chkreports,
160+
input: $("#userinput")[0].value
161+
};
162+
const time = new Date().Format("yyyyMMdd-hhmm");
163+
DownloadMan.exportDownload(state, "json", `AutoSpider-state-${time}.json`);
164+
});
165+
$("body").on("dragover", "#bakstate", ev => ev.preventDefault());
166+
$("body").on("drop", "#bakstate", ev =>
167+
{
168+
ev.preventDefault();
169+
const files = ev.originalEvent.dataTransfer.files;
170+
if (files.length <= 0)
171+
return;
172+
const reader = new FileReader();
173+
reader.onload = e =>
174+
{
175+
const content = e.target.result;
176+
const state = JSON.parse(content);
177+
console.log(state);
178+
uids.clear();
179+
rowcount = 0;
180+
thetable.clear();
181+
state.users.forEach(usr =>
182+
{
183+
let user = new User();
184+
Object.assign(user, usr);
185+
uids.set(user.id, user);
186+
const newdata = { usr: { id: user.id, name: user.name }, index: rowcount++ };
187+
Object.assign(newdata, user);
188+
thetable.row.add(newdata);
189+
});
190+
utimeOld = new Map(state.utimeOld);
191+
utimeNew = new Map(state.utimeNew);
192+
u404s = new Set(state.u404s);
193+
Object.assign(chkreports, state.chkreports);
194+
$("#userinput")[0].value = state.input;
195+
thetable.draw(false);
196+
}
197+
reader.readAsText(files[0]);
198+
});
139199
$(document).on("click", "#export", e =>
140200
{
141201
const btn = e.target;
@@ -145,9 +205,9 @@ $(document).on("click", "#export", e =>
145205
const time = new Date().Format("yyyyMMdd-hhmm");
146206
DownloadMan.exportDownload(res, "json", `AutoSpider-${time}.json`);
147207
});
148-
$(document).on("click", "#import", e =>
208+
$(document).on("click", "#import", ev =>
149209
{
150-
const btn = e.target;
210+
const btn = ev.target;
151211
const files = $("#infile")[0].files;
152212
if (files.length <= 0)
153213
return;
@@ -236,6 +296,7 @@ $(document).on("click", "#go", async e =>
236296
return;
237297
}
238298
isRunning = true;
299+
curBtn = btn;
239300
const isCtrl = e.ctrlKey;
240301
try
241302
{
@@ -256,16 +317,8 @@ $(document).on("click", "#go", async e =>
256317
{
257318
console.warn(e);
258319
isRunning = false;
320+
curBtn.style.background = "";
321+
curBtn = null;
259322
}
260323
});
261324

262-
chrome.runtime.onMessage.addListener(data=>
263-
{
264-
if (data.id === "cookie")
265-
{
266-
console.log("recieve cookie", data.val);
267-
const xudidstr = _getTheCookie("d_c0", data.val);
268-
if (xudidstr)
269-
ContentBase.CUR_TOKEN = new UserToken2(xudidstr.split("|")[0]);
270-
}
271-
});

ZhiHuExt/ContentBase.js

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
let _CUR_USER;
66
let _CUR_ANSWER;
77
let _CUR_QUESTION;
8-
/**@type {UserToken|UserToken2}*/
8+
/**@type {UserToken}*/
99
let _CUR_TOKEN;
1010
/**@type {HTMLScriptElement}*/
1111
let _CUR_HOOKER;
@@ -40,14 +40,15 @@ class ContentBase
4040
* @param {"answer" | "article"} obj
4141
* @param {number | string} id
4242
* @param {number} offset
43+
* @param {object} header
4344
* @returns {Promise<{users: User[], end: boolean, start: boolean, total: number}>}
4445
*/
45-
static _fetchAnsVoters(obj, id, offset)
46+
static _fetchAnsVoters(obj, id, offset, header)
4647
{
4748
const part = (obj === "answer") ? "voters" : "likers";
4849
const zanquery = (obj === "answer") ? ",voteup_count" : "";
4950
const pms = $.Deferred();
50-
ContentBase._get(`https://www.zhihu.com/api/v4/${obj}s/${id}/${part}?include=data[*].answer_count,articles_count,follower_count${zanquery}&limit=20&offset=${offset}`)
51+
ContentBase._get(`https://www.zhihu.com/api/v4/${obj}s/${id}/${part}?include=data[*].answer_count,articles_count,follower_count${zanquery}&limit=20&offset=${offset}`, undefined, header)
5152
.done((data, status, xhr) =>
5253
{
5354
const users = data.data.map(User.fromRawJson);
@@ -122,10 +123,23 @@ class ContentBase
122123
return pms;
123124
}
124125

126+
static _xhr()
127+
{
128+
const xhr = $.ajaxSettings.xhr();
129+
const oldSetter = xhr.setRequestHeader;
130+
xhr.setRequestHeader = (name, val) =>
131+
{
132+
if (name.toLowerCase() !== "x-requested-with")
133+
oldSetter.call(xhr, name, val);
134+
}
135+
return xhr;
136+
}
137+
125138
static _get(url, data, headers)
126139
{
127140
return $.ajax(url,
128141
{
142+
xhr: ContentBase._xhr,
129143
type: "GET",
130144
data: data,
131145
headers: headers,
@@ -147,6 +161,7 @@ class ContentBase
147161
}
148162
return $.ajax(url,
149163
{
164+
xhr: ContentBase._xhr,
150165
type: "POST",
151166
contentType: cType,
152167
headers: headers,
@@ -209,8 +224,9 @@ class ContentBase
209224
*/
210225
static async fetchTheVoters(obj, id, limit, config, onProgress)
211226
{
227+
const tokenhead = ContentBase.CUR_TOKEN ? ContentBase.CUR_TOKEN.toHeader() : {};
212228
let errcnt = 0;
213-
const first = await ContentBase._fetchAnsVoters(obj, id, 0);
229+
const first = await ContentBase._fetchAnsVoters(obj, id, 0, tokenhead);
214230
/**@type {User[]}*/
215231
let ret = config === "old+" ? [] : first.users;
216232
let oldtotal = first.total, demand = Math.min(oldtotal, limit)
@@ -226,7 +242,7 @@ class ContentBase
226242
{
227243
try
228244
{
229-
const part = await ContentBase._fetchAnsVoters(obj, id, offset);
245+
const part = await ContentBase._fetchAnsVoters(obj, id, offset, tokenhead);
230246
const newtotal = part.total;
231247
const newusrs = part.users.filter(u => !usrset.has(u.id));
232248
newusrs.forEach(u => usrset.add(u.id));
@@ -263,6 +279,7 @@ class ContentBase
263279
let time = begintime || new Date().toUTCSeconds();
264280
limittime = limittime || ContentBase.BASE_LIM_DATE;
265281
const tokenhead = ContentBase.CUR_TOKEN ? ContentBase.CUR_TOKEN.toHeader() : {};
282+
tokenhead["x-api-version"] = "3.0.40";
266283
const ret = new StandardDB();
267284
let isEnd = false;
268285
for (let i = 0; i < maxloop && time > limittime && !isEnd; ++i)
@@ -462,6 +479,12 @@ class ContentBase
462479
}
463480
return pms;
464481
}
482+
483+
/**@param {string} [cookie]*/
484+
static prepareToken(cookie)
485+
{
486+
ContentBase.CUR_TOKEN = new UserToken(_getCookie(cookie))
487+
}
465488
}
466489

467490
/**@param e {CustomEvent}*/
@@ -474,19 +497,25 @@ function hookerHandler(e)
474497
const oldId = ContentBase.CUR_TOKEN && ContentBase.CUR_TOKEN.xUDID;
475498
if (e.detail.udid != oldId)
476499
{
477-
ContentBase.CUR_TOKEN = new UserToken2(e.detail.udid);
500+
ContentBase.CUR_TOKEN = new UserToken(e.detail.udid);
478501
console.log("UDID changed:", oldId, e.detail.udid, e);
479502
}
480503
} break;
481504
}
482505
}
483506

484507
{
485-
const xudidstr = _getTheCookie("d_c0");
486-
if (xudidstr)
508+
ContentBase.prepareToken();
509+
chrome.runtime.onMessage.addListener(data=>
487510
{
488-
ContentBase.CUR_TOKEN = new UserToken2(xudidstr.split("|")[0]);
489-
}
511+
if (data.id === "cookie")
512+
{
513+
//console.log("recieve cookie", data.val);
514+
ContentBase.prepareToken(data.val);
515+
console.log("[current token]", ContentBase.CUR_TOKEN);
516+
}
517+
});
518+
fetch("https://api.zhihu.com/getcookie", { credentials: "include" });
490519
const obs = new MutationObserver(records =>
491520
{
492521
for (let i = 0; i < records.length; ++i)
@@ -504,8 +533,8 @@ function hookerHandler(e)
504533
{
505534
obs.disconnect();
506535
_CUR_HOOKER = node;
507-
node.addEventListener("ZHHookerNotify", hookerHandler);
508-
console.log("[ZHIHU_Hook] inked!");
536+
//node.addEventListener("ZHHookerNotify", hookerHandler);
537+
console.log("[ZHIHU_Hook] linked!");
509538
return;
510539
}
511540
}

ZhiHuExt/CookieHooker.js

Lines changed: 0 additions & 6 deletions
This file was deleted.

ZhiHuExt/PageEnhance.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,15 +286,22 @@ function reportEnhance()
286286
return;
287287
}
288288
chkAll.dataset.isChecking = "true";
289-
/**@type {HTMLButtonElement[]}*/
290-
const btns = $("button.Btn-QCheckStatus", document).toArray()
291-
.filter(x => x.style.background === "");
292-
for (let i = 0; i < btns.length && chkAll.dataset.isChecking === "true"; ++i)
289+
try
293290
{
294-
chkAll.textContent = btns[i].dataset.name;
295-
await Promise.all([onChkStatus({ target: btns[i] }), _sleep(1200)]);
291+
/**@type {HTMLButtonElement[]}*/
292+
const btns = $("button.Btn-QCheckStatus", document).toArray()
293+
.filter(x => x.style.background === "");
294+
for (let i = 0; i < btns.length && chkAll.dataset.isChecking === "true"; ++i)
295+
{
296+
chkAll.textContent = btns[i].dataset.name;
297+
await Promise.all([onChkStatus({ target: btns[i] }), _sleep(1200)]);
298+
}
299+
}
300+
finally
301+
{
302+
chkAll.dataset.isChecking = "false";
303+
chkAll.textContent = "检测全部";
296304
}
297-
chkAll.textContent = "检测全部";
298305
});
299306
{
300307
const dummydiv = makeElement("div", [], { style: { textAlign: "center" } }, chkAll);

ZhiHuExt/ZhiHuHooker.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@
8484
*/
8585
async function newfetch(req, init)
8686
{
87-
if (init && init.headers && init.headers.hasOwnProperty("X-UDID") && selfDom)
88-
{
89-
selfDom.dispatchEvent(new CustomEvent("ZHHookerNotify", {detail: {udid: init.headers["X-UDID"], type: "udid"}}));
90-
}
87+
// if (init && init.headers && init.headers.hasOwnProperty("X-UDID") && selfDom)
88+
// {
89+
// selfDom.dispatchEvent(new CustomEvent("ZHHookerNotify", {detail: {udid: init.headers["X-UDID"], type: "udid"}}));
90+
// }
9191
if (!req.includes("www.zhihu.com/api/v"))
9292
return oldfetch(req, init);
9393
const apiparts = req.substring(req.indexOf("/api/v") + 8, req.indexOf("?")).split("/");

0 commit comments

Comments
 (0)