Correctly handle Tsinghua Learn homework workflows: locate the assignment, download the prompt, read the instructions, submit the right file, and verify the result.
Use this skill for the full Tsinghua Learn homework workflow, not just uploading a file.
Goals:
Use this skill when:
alma browser tabs
Look for tabs like:
https://learn.tsinghua.edu.cn/...Operating SystemsIf you are not already on an assignment page, navigate from the course page.
alma browser read <tabId>
alma browser read-dom <tabId>
Verify all of the following:
Assignment list pages are usually like:
/f/wlxt/kczy/zy/student/beforePageList?...You can extract the table with:
alma browser eval <tabId> "(() => {
const rows=[...document.querySelectorAll('table tr')]
.map(tr => [...tr.querySelectorAll('td')].map(td => td.innerText.trim().replace(/\\n+/g,' | ')))
.filter(r => r.length);
return JSON.stringify(rows, null, 2);
})()"
If you want the detail link for each row:
alma browser eval <tabId> "(() => {
const rows=[...document.querySelectorAll('table tr')].map(tr => [...tr.querySelectorAll('td')]);
const items=rows.filter(tds => tds.length >= 6).map(tds => ({
title: tds[1]?.innerText.trim(),
href: tds[1]?.querySelector('a')?.href || ''
}));
return JSON.stringify(items, null, 2);
})()"
Then open the target assignment detail page.
Assignment detail pages are usually like:
/f/wlxt/kczy/zy/student/viewZy?...Read them with:
alma browser read <tabId>
alma browser read-dom <tabId>
If alma browser read does not extract the content cleanly, fall back to:
alma browser eval <tabId> "document.body.innerText"
Extract at least:
Do not guess download URLs with curl first.
Instead, first inspect the DOM on the assignment detail page and collect the attachment links:
alma browser eval <tabId> "(() => JSON.stringify(
[...document.querySelectorAll('a')]
.map(a => ({text:(a.innerText||'').trim(), href:a.href}))
.filter(x => x.text || x.href.includes('downloadFile')),
null, 2
))()"
Common cases:
Download link nearby_csrf parameterAfter you have the link, prefer opening it in the browser so the site can use the existing login session:
alma browser open "<attachment-url>"
If the site says the file cannot be previewed and will be downloaded automatically, continue and confirm.
Then find the newly downloaded local file:
find ~/Downloads -maxdepth 1 -type f -mmin -5 -print0 | xargs -0 ls -lt | head
Once the file is on disk, read the local file itself instead of guessing from the preview page.
Examples:
Read /Users/.../Homework4.md
Read /Users/.../HW4.txt
If it is a PDF, prefer checking whether there is also a markdown, doc, or txt version first. If not, use an appropriate PDF-reading path afterward.
First open the submission page:
/f/wlxt/kczy/zy/student/tijiao?...If the detail page has a submit button, use that first. Otherwise, inspect page scripts or functions such as goBtnF() to find the target submission URL.
Once on the submission page, confirm these important elements:
#form_sn1#fileupload#goBtn or input[value='提交']#s_documention or name='zynr'Check the form with:
alma browser eval <tabId> "(() => JSON.stringify({
action: document.querySelector('#form_sn1')?.action || '',
fileInput: !!document.querySelector('#fileupload'),
submitBtn: document.querySelector('#goBtn')?.outerHTML || document.querySelector(\"input[value='提交']\")?.outerHTML || ''
}, null, 2))()"
After uploading a file, confirm that it really entered input.files:
alma browser eval <tabId> "(() => {
const el=document.querySelector('#fileupload');
return JSON.stringify({
len: el?.files?.length || 0,
name: el?.files?.[0]?.name || '',
size: el?.files?.[0]?.size || 0
}, null, 2);
})()"
Only continue if len = 1.
You can usually submit by calling the page’s own function:
alma browser eval <tabId> "daijiao(); 'submitted';"
After submission, the page often returns to the assignment list.
If the file picker, file input, or frontend scripts keep breaking, directly send a multipart request using the current browser session and XSRF token.
First read the form parameters:
alma browser eval <tabId> "(() => {
const form=document.querySelector('#form_sn1');
return JSON.stringify({
xszyid: form?.querySelector(\"input[name='xszyid']\")?.value || '',
isDeleted: form?.querySelector(\"input[name='isDeleted']\")?.value || '0',
zynr: form?.querySelector(\"textarea[name='zynr']\")?.value || ''
}, null, 2);
})()"
Convert the local file to base64:
python3 - <<'PY' > /tmp/alma_hw_b64.txt
import base64
with open('/ABS/PATH/TO/FILE.pdf','rb') as f:
print(base64.b64encode(f.read()).decode())
PY
Then construct File and FormData inside the page context:
b64=$(cat /tmp/alma_hw_b64.txt)
alma browser eval <tabId> "window.__almaSubmitResult='pending'; (function(){
const b64='$b64';
const bin=atob(b64);
const arr=new Uint8Array(bin.length);
for(let i=0;i<bin.length;i++) arr[i]=bin.charCodeAt(i);
const fd=new FormData();
fd.append('xszyid','<xszyid>');
fd.append('isDeleted','0');
fd.append('zynr','');
fd.append('fileupload', new File([arr], '<filename.pdf>', {type:'application/pdf'}));
fetch('/b/wlxt/kczy/zy/student/tjzy', {
method:'POST',
body:fd,
headers:{'X-XSRF-TOKEN':(document.cookie.match(/(?:^|; )XSRF-TOKEN=([^;]+)/)||[])[1]||''},
credentials:'include'
}).then(async r => {
window.__almaSubmitResult = JSON.stringify({
ok:r.ok,
status:r.status,
text:(await r.text()).slice(0,1500)
});
}).catch(e => window.__almaSubmitResult='ERR:'+e);
return 'started';
})()"
Poll the result:
sleep 3
alma browser eval <tabId> "window.__almaSubmitResult || 'missing'"
Do not rely only on whether the page showed an error.
Always return to the assignment list page and inspect the target row to see whether it now shows an attachment size and submission status.
Example:
alma browser eval <tabId> "(() => {
const rows=[...document.querySelectorAll('table tr')]
.map(tr => [...tr.querySelectorAll('td')].map(td => td.innerText.trim().replace(/\\n+/g,' | ')))
.filter(r => r.length);
return JSON.stringify(rows, null, 2);
})()"
Typical success signals:
214.36K提交作业收藏备注 or other evidence of a recorded submissionBefore every submission, confirm all of these:
input.files[0].name matches the expected file.A good final pre-submit summary is one short sentence like:
/Users/.../OS/hw/Homework4.pdfChromeRelayUpload returning success does not guarantee the file entered the form.
input.files.#goBtn or the bottom input[value='提交'].When the task is done, report in one short sentence:
Example:
Re-submitted successfully: Operating Systems / Homework 4 now shows the correct 214.36K PDF in the assignment list.The correct order for Tsinghua Learn homework is not “upload first and check later”.
It should always be:
Find the right course and assignment → download and read the prompt → produce the correct file → verify the absolute path → upload → verify from the assignment list.