Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4290b03

Browse files
committed
first version
1 parentde0515e commit4290b03

File tree

6 files changed

+320
-4
lines changed

6 files changed

+320
-4
lines changed

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
gmail_app_pswd
2+
13
# Byte-compiled / optimized / DLL files
24
__pycache__/
35
*.py[cod]

‎README.md‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
1-
#webpage-monitor
1+
#webpage-monitor
2+
3+
A macOS-based webpage monitor that sends you an email of a webpage's before
4+
and after when changes are detected.
5+
6+
7+
##Installing
8+
9+
1. Install`webkit2png` with:
10+
```
11+
brew install webkit2png
12+
```

‎roster.json‎

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
{
2+
"https://people.csail.mit.edu/xiuming/": {
3+
},
4+
"https://people.csail.mit.edu/abulnaga/": {
5+
},
6+
"https://taichi.graphics/me/": {
7+
},
8+
"https://people.csail.mit.edu/recasens/": {
9+
},
10+
"https://andrewowens.com/": {
11+
},
12+
"https://people.eecs.berkeley.edu/~kanazawa/": {
13+
},
14+
"https://web.mit.edu/torralba/www/": {
15+
},
16+
"https://sites.google.com/view/yushengmath": {
17+
},
18+
"https://bailiu.me/": {
19+
},
20+
"https://tonyzhang25.github.io/": {
21+
},
22+
"https://bzhou.ie.cuhk.edu.hk/": {
23+
},
24+
"https://web.stanford.edu/~chengxuz/": {
25+
},
26+
"https://people.csail.mit.edu/ganchuang/": {
27+
},
28+
"https://people.csail.mit.edu/davidbau/home/": {
29+
},
30+
"https://distill.pub/": {
31+
},
32+
"https://donglaiw.github.io/": {
33+
},
34+
"https://people.csail.mit.edu/janner/": {
35+
},
36+
"https://people.csail.mit.edu/mingmin/": {
37+
},
38+
"https://www.mit.edu/~geliu/": {
39+
},
40+
"https://sites.google.com/view/yeolab/thomas?authuser=0": {
41+
},
42+
"https://people.csail.mit.edu/balakg/": {
43+
},
44+
"https://ai.stanford.edu/~hewang/": {
45+
},
46+
"https://hxu.rocks/": {
47+
},
48+
"https://ztzhang.info": {
49+
},
50+
"https://jiajunwu.com/": {
51+
},
52+
"https://jiayuanm.com/": {
53+
},
54+
"https://people.csail.mit.edu/jiex/": {
55+
},
56+
"https://www.cs.princeton.edu/~jw60/": {
57+
},
58+
"https://jonbarron.info/": {
59+
},
60+
"https://people.csail.mit.edu/junyanz/": {
61+
},
62+
"https://kaiminghe.com/": {
63+
},
64+
"https://users.cms.caltech.edu/~klbouman/": {
65+
},
66+
"https://people.csail.mit.edu/miika/": {
67+
},
68+
"https://people.csail.mit.edu/nwadhwa/": {
69+
},
70+
"https://txie.me/publications/": {
71+
},
72+
"https://people.csail.mit.edu/hangzhao/": {
73+
},
74+
"https://web.mit.edu/renboz/www/": {
75+
},
76+
"https://people.csail.mit.edu/ruizhi/": {
77+
},
78+
"https://wx405557858.github.io/": {
79+
},
80+
"https://www.mit.edu/~lishuang/": {
81+
},
82+
"https://sites.google.com/a/eng.ucsd.edu/zhengqinli/": {
83+
},
84+
"https://people.csail.mit.edu/talidekel/": {
85+
},
86+
"https://people.csail.mit.edu/taodu/": {
87+
},
88+
"https://people.csail.mit.edu/tiam/": {
89+
},
90+
"https://people.eecs.berkeley.edu/~tinghuiz/": {
91+
},
92+
"https://ssnl.github.io/": {
93+
},
94+
"https://thepointsguy.com/download/": {
95+
},
96+
"https://people.eecs.berkeley.edu/~vye/": {
97+
},
98+
"https://people.csail.mit.edu/weichium/": {
99+
},
100+
"https://people.csail.mit.edu/weiqiaoh/": {
101+
},
102+
"https://people.csail.mit.edu/liangs/": {
103+
},
104+
"https://people.csail.mit.edu/wengong/": {
105+
},
106+
"https://people.csail.mit.edu/xavierpuig/": {
107+
},
108+
"https://people.csail.mit.edu/xingyuan/": {
109+
},
110+
"https://scholar.google.com/citations?user=5hl9MqMAAAAJ&hl=en": {
111+
},
112+
"https://people.csail.mit.edu/tfxue/": {
113+
},
114+
"https://homes.cs.washington.edu/~yifan1/": {
115+
},
116+
"https://people.csail.mit.edu/yonglong/": {
117+
},
118+
"https://people.csail.mit.edu/wangyu9/": {
119+
},
120+
"https://people.csail.mit.edu/yuewang/": {
121+
},
122+
"https://people.csail.mit.edu/liyunzhu/": {
123+
},
124+
"https://www.cs.cornell.edu/~zl548/": {
125+
}
126+
}

‎run.py‎

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env python3
2+
3+
importargparse
4+
fromos.pathimportjoin,exists
5+
fromosimportmakedirs,remove
6+
fromglobimportglob
7+
importjson
8+
fromtimeimporttime
9+
importnumpyasnp
10+
fromtqdmimporttqdm
11+
fromPILimportImage
12+
13+
importutil
14+
15+
16+
parser=argparse.ArgumentParser(description="Webpage monitor.")
17+
parser.add_argument(
18+
'--roster_json',type=str,default='./roster.json',help="path to the roster")
19+
parser.add_argument(
20+
'--check_every',type=int,default=600,help="check every N seconds")
21+
parser.add_argument(
22+
'--exit_after',type=int,default=None,help="quit after N seconds")
23+
parser.add_argument(
24+
'--tmp_dir',type=str,default='/tmp/webpage-monitor',
25+
help="directory to dump screenshots for comparison")
26+
27+
28+
defmain(args):
29+
ifargs.exit_afterisNone:
30+
exit_after=np.inf
31+
else:
32+
exit_after=args.exit_after
33+
34+
roster=load_roster(args.roster_json)
35+
36+
start_t=time()
37+
last_check_t=0
38+
39+
whileTrue:
40+
iftime()-last_check_t>args.check_every:
41+
changed= []
42+
43+
forurl,optintqdm(roster.items(),desc="Checking URLs"):
44+
out_dir=join(args.tmp_dir,url.replace('/','_'))
45+
46+
# Take screenshots
47+
screenshot(url,out_dir,opt)
48+
49+
pngs=sorted(glob(join(out_dir,'*.png')))
50+
51+
# Compare with previous screenshots
52+
iflen(pngs)>1:
53+
ifdiff(*pngs[-2:]):
54+
changed.append(url)
55+
56+
# Remove earlier screenshots to avoid storage explosion
57+
iflen(pngs)>2:
58+
forfinpngs[:-2]:
59+
remove(f)
60+
61+
last_check_t=time()
62+
63+
# Email myself the results
64+
ifchanged:
65+
msg='\n'.join(changed)
66+
util.email_myself(msg,subject="Webpage Monitor")
67+
util.format_print("Change detected; email sent",'okgreen')
68+
# from IPython import embed; embed()
69+
70+
iftime()-start_t>exit_after:
71+
break
72+
73+
74+
defdiff(png1,png2,thres=0.1):
75+
im1=Image.open(png1)
76+
im2=Image.open(png2)
77+
im1=np.array(im1)
78+
im2=np.array(im2)
79+
80+
# Check size
81+
ifim1.shape!=im2.shape:
82+
returnTrue
83+
84+
# Check content
85+
im1=im1.astype(float)/np.iinfo(im1.dtype).max
86+
im2=im2.astype(float)/np.iinfo(im2.dtype).max
87+
diff_im=np.abs(im1-im2)
88+
return (diff_im>=thres).any()
89+
90+
91+
defscreenshot(url,out_dir,opt,width=1080,delay=3):
92+
ifnotexists(out_dir):
93+
makedirs(out_dir)
94+
95+
cmd= (
96+
'webkit2png --fullsize --ignore-ssl-check --width={w} --delay={delay} '
97+
'--dir={dir_} --filename={t} {url}').format(
98+
w=width,delay=delay,dir_=out_dir,t=time(),url=url)
99+
util.call(cmd,silence_stdout=True)
100+
101+
102+
defload_roster(roster_json):
103+
withopen(roster_json,'r')ash:
104+
roster=json.load(h)
105+
returnroster
106+
107+
108+
if__name__=='__main__':
109+
main(parser.parse_args())

‎run_monitor.py‎

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

‎util.py‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
fromsubprocessimportPopen,PIPE
2+
fromemail.mime.textimportMIMEText
3+
importsmtplib
4+
5+
6+
defcall(cmd,cwd=None,silence_stdout=False):
7+
process=Popen(cmd,stdout=PIPE,stderr=PIPE,cwd=cwd,shell=True)
8+
9+
stdout,stderr=process.communicate()# waits for completion
10+
stdout,stderr=stdout.decode(),stderr.decode()
11+
12+
ifnotsilence_stdout:
13+
ifstdout!='':
14+
format_print(stdout,'okblue')
15+
16+
ifstderr!='':
17+
format_print(cmd,'header')
18+
format_print(stderr,'fail')
19+
20+
21+
defemail_myself(
22+
msg,subject="Untitled",email='xiuming6zhang@gmail.com',
23+
pswd_path='./gmail_app_pswd'):
24+
withopen(pswd_path,'r')ash:
25+
pswd=h.readlines()
26+
pswd=pswd[0].strip()
27+
28+
to_emails= [email]
29+
from_email=email
30+
31+
msg=MIMEText(msg)
32+
msg['Subject']=subject
33+
msg['To']=', '.join(to_emails)
34+
msg['From']=from_email
35+
36+
mail=smtplib.SMTP('smtp.gmail.com',587)
37+
mail.starttls()
38+
mail.login(email,pswd)
39+
mail.sendmail(from_email,to_emails,msg.as_string())
40+
mail.quit()
41+
42+
43+
defformat_print(msg,fmt):
44+
"""Prints a message with format.
45+
Args:
46+
msg (str): Message to print.
47+
fmt (str): Format; try your luck with any value -- don't worry; if
48+
it's illegal, you will be prompted with all legal values.
49+
Raises:
50+
ValueError: If the input format is illegal.
51+
"""
52+
fmt_strs= {
53+
'header':'\033[95m',
54+
'okblue':'\033[94m',
55+
'okgreen':'\033[92m',
56+
'warn':'\033[93m',
57+
'fail':'\033[91m',
58+
'bold':'\033[1m',
59+
'underline':'\033[4m'}
60+
iffmtinfmt_strs.keys():
61+
start_str=fmt_strs[fmt]
62+
end_str='\033[0m'
63+
eliflen(fmt)==1:
64+
start_str="\n<"+"".join([fmt]*78)+'\n\n'# as per PEP8
65+
end_str='\n'+start_str[2:-2]+">\n"
66+
else:
67+
raiseValueError(
68+
("Legal values for fmt: %s, plus any single character "
69+
"(which will be repeated into the line separator), "
70+
"but input is '%s'")% (list(fmt_strs.keys()),fmt))
71+
print(start_str+msg+end_str)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp