Web上からデータを引っ張ってくるコード
HEP Postdoc Rumor Mill の2013年~2021年のデータから各人間がどこからオファーが来て、どの機関のオファーをacceptしたかを抽出。from selenium import webdriver from selenium.webdriver.chrome.options import Options from bs4 import BeautifulSoup from collections import defaultdict def purify(inst,stat): # 機関名の表記の揺れを統一 if "It from Qubit" in inst or "It from Qubit" in stat: return "It from Qubit" elif "Princeton" in inst: return "Princeton" elif "Stanford" in inst: return "Stanford" elif "Berkeley" in inst: return "UC Berkeley" elif "KITP" in inst: return "KITP" elif "Fermilab" in inst: return "Fermilab" elif "New York U." in inst: return "New York U." elif "Peking U." in inst: return "Peking U." elif "Tsinghua U." in inst: return "Tsinghua U." elif "UC Davis" in inst: return "UC Davis" elif "AEI" in inst: return "Albert Einstein Institute" elif "IPMU" in inst: return "Kavli IPMU" elif "Cambridge" in inst: return "Cambridge U." elif "McGill" in inst: return "McGill" else: return inst priority=defaultdict(int) #ここに抽出データを保存 # html取得 (2013~2016 とそれ以降でhtmlの形式が変わっているので、別々に処理する必要がある。以下では2017~を扱っている。) option = Options() option.add_argument('--headless') driver = webdriver.Chrome("C:\ProgramData\Anaconda3\Lib\site-packages\selenium\webdriver\chromedriver.exe", options=option) links=[ "https://docs.google.com/spreadsheets/u/0/d/1tZAdZ_Q44CnGGvCWnPDXVBiYHxF-ti0G5RWJwXBwLtk/htmlembed/sheet?headers=false&gid=0", "https://docs.google.com/spreadsheets/u/0/d/11Itq4eZBzNsjlSQGnfYib6Obiw59yToG34cC_eBYXeo/htmlembed/sheet?headers=false&gid=0", "https://docs.google.com/spreadsheets/u/0/d/1GV_ebj7-Itxy7Pb19Yja7a1f0J2FXuGYvMkRBhmuSBo/htmlembed/sheet?headers=false&gid=0", "https://docs.google.com/spreadsheets/u/0/d/1u4RuIFetw_ZNg0APlXhnbkqqYzjS2xSV9sBx0NxxfPo/htmlembed/sheet?headers=false&gid=0", "https://docs.google.com/spreadsheets/u/0/d/1iMsLRnNNHFKmdq7ltrp9BR4jDd-Ots6UYDK2dgyRLZ0/htmlembed/sheet?headers=false&gid=0" ] for link in links: driver.get(link) html = driver.page_source soup = BeautifulSoup(html, "lxml") accepted=dict() declined=defaultdict(list) offered=defaultdict(list) for tbody in soup.find("tbody"): name, link, inst, stat, time=[td.get_text().strip() for td in tbody.find_all("td")] # name, link, inst, stat, time は見た目の通りのデータなので、これを使い道に応じて弄ると良い inst=purify(inst,stat) if "Accepted" in stat: accepted[name]=inst if "Declined" in stat: declined[name].append(inst) if "Offered" in stat: offered[name].append(inst) for name, inst1 in accepted.items(): if not declined.get(name): continue for inst2 in declined[name]: priority[inst1,inst2]+=1 for inst2 in offered[name]: if inst1!=inst2 and inst2 not in declined[name]: priority[inst1,inst2]+=1 # html取得 (2013~2016 とそれ以降でhtmlの形式が変わっているので、別々に処理する必要がある。以下では~2016を扱っている。) links=[ "https://sites.google.com/site/postdocrumor/2016-rumors", "https://sites.google.com/site/postdocrumor/2015-rumors", "https://sites.google.com/site/postdocrumor/2014-rumors", "https://sites.google.com/site/postdocrumor/2013-rumors" ] for link in links: driver.get(link) html = driver.page_source soup = BeautifulSoup(html, "lxml") accepted=dict() declined=defaultdict(list) offered=defaultdict(list) for tr in soup.find("table", id="goog-ws-list-table").find_all("tr")[1:]: name, inst, stat, time=[td.get_text().strip() for td in tr.find_all("td")] # name, inst, stat, time は見た目の通りのデータなので、これを使い道に応じて弄ると良い inst=purify(inst,stat) if "Accepted" in stat: accepted[name]=inst if "Declined" in stat: declined[name].append(inst) if "Offered" in stat: offered[name].append(inst) for name, inst1 in accepted.items(): if not declined.get(name): continue for inst2 in declined[name]: priority[inst1,inst2]+=1 for inst2 in offered[name]: if inst1!=inst2 and inst2 not in declined[name]: priority[inst1,inst2]+=1 ####################################################################################### # 優先度の不等式をグラフにしている。こうするとプログラマー的に扱いやすい気がする。 # 強連結成分分解して色々したら、全体ランキングみたいなのを作れるかなとも思ったが、上手くいかず。 # いいアイデアください。 code=dict() decode=dict() N=0 edges=[] inv_edges=[] for (a,b),cost in priority.items(): if priority[a,b]>priority.get((b,a),0): if not code.get(a): code[a]=N; decode[N]=a; N+=1; edges.append([]); inv_edges.append([]) if not code.get(b): code[b]=N; decode[N]=b; N+=1; edges.append([]); inv_edges.append([]) A,B=code[a],code[b] edges[A].append(B) inv_edges[B].append(A) ####################################################################################### print("*lord completed*") # ここから、対話形式を実現するコード # 機関名 A の入力に対して、抽出したデータを元に色々する。 while True: A=input().rstrip() if not code.get(A): print("No Comparisons"); continue a=code[A] res1=[] res2=[] for b in edges[a]: B=decode[b] x,y=priority.get((A,B),0),priority.get((B,A),0) p=x/(x+y) res1.append((B,p,x,y)) for b in inv_edges[a]: B=decode[b] x,y=priority.get((A,B),0),priority.get((B,A),0) p=x/(x+y) res2.append((B,p,x,y)) res1.sort(key=lambda x:x[2]+x[3], reverse=True) res1.sort(key=lambda x:x[1],reverse=True) res2.sort(key=lambda x:x[2]+x[3], reverse=True) res2.sort(key=lambda x:x[1],reverse=True) for inst, p, x, y in res1: print("vs. {}: {}/{}".format(inst,x,x+y)) for inst, p, x, y in res2: print("vs. {}: {}/{}".format(inst,x,x+y))