有機化学の研究者をはじめ、ごく一部の方にとって非常に有意義なプログラムになると思います。
##背景##
化学実験で用いる全ての試薬には、それぞれに対応した安全データシート(SDS)なるものがあります。
その管理は安全衛生上、非常に大事なものです。しかし、有機系の研究室ともなれば数百、いや下手したら数千もの試薬を所持しています。その膨大なSDSについて毎年調べるのは正直面倒くさい。。
そんな研究者は日本全国きっと多いはずです。
なので、今回SDSの探索を自動化しました!
##概要##
タイトルのまんまです。
入力した試薬のSDSのPDFデータを調べ、保存するプログラムです。
##実行環境&使用したもの##
windows10
anaconda(Python3)Spyder (GoogleColab及びJupyterでも実行可能)
サイト:日本試薬協会(https://www.j-shiyaku.or.jp/Sds )
ライブラリ:selenium、BeautifulSoup、chromeDriver etc..
##ソースコード##
ライブラリのインストールがされてれば、コピペで行ける(はず)。
長いのであんまり説明する気にならないです。
でも、難しい構文は使ってないので、皆さんならきっと大丈夫でしょう。
ややこしいのは再帰処理くらいかな、と。
import time
import openpyxl
from openpyxl.styles import PatternFill
from bs4 import BeautifulSoup#解析用。非常に高速
import requests
import re
from selenium import webdriver#web操作用。いちいちchromeを展開するので遅い
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import urllib.request as req#URL-->PDF保存用
import urllib
#from google.colab import drive
#drive.mount('/content/drive')
#↓に"Mounted at /content/drive"と出力されればgoogleDriveと接続完了
def changeComp(compNo,key,newUrl,sheet):
global Row
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome('chromedriver') #visible
#driver = webdriver.Chrome('chromedriver',options=options) #NOT visible
driver.implicitly_wait(10) #
driver.get(newUrl[compNo])
#検索テキストボックスの要素をId属性名から取得&文字列を(key)入力
driver.find_element_by_id("InputWord").clear()
driver.find_element_by_id("InputWord").send_keys(key)
#class名から検索ボタを指定しクリック
driver.find_element_by_class_name('btn_c_submit').click()
#keyの検索結果数取得
searchNo=int(re.sub(r"\D", "", driver.find_element_by_class_name("kakoi1").text))
if searchNo==0 and (compNo+1)<len(newUrl):
driver.quit()
return changeComp(compNo+1,key,newUrl,sheet)#ここで再起処理
elif searchNo>0:
sheet.cell(row=Row, column=2).value=key
sheet.cell(row=Row, column=3).value=searchNo
saveURL(driver,key,sheet,compNo)
driver.quit()
return True
driver.quit()
return False#全て0の場合
def saveURL(driver,key,sheet,compNo):
global Row,companys,urlHead,cNo
cas=[]
print(key + " is found!")
#次ページがあれば繰り返し
while True:
urlPdf=[]
urlPdf=driver.find_elements_by_class_name('clickable')
#print((urlPdf))
nextButton=driver.find_elements_by_name("submit2")
pageNo=len(nextButton)
for i in range(len(urlPdf)):
text=urlPdf[i].text.split("\n")
#print(text)
for j in range(len(cas)):
if cas[j]==text[2+cNo].split(" ")[0]:
break
else:
try:
cas.append(text[2+cNo].split(" ")[0])#cas
except IndexError:
#print(111)
cNo-=1
cas.append(text[2+cNo].split(" ")[1])#cas
sheet.cell(row=Row, column=4).value=text[0+cNo]#name
if text[0+cNo]==key:
sheet.cell(row=Row, column=4).fill=openpyxl.styles.PatternFill(patternType='solid',fgColor='FF0000', bgColor='FF0000')
sheet.cell(row=Row, column=5,).value=text[1+cNo]#enname
sheet.cell(row=Row, column=6).value=cas[-1]
sheet.cell(row=Row, column=7).hyperlink=(urlHead + urlPdf[i].get_attribute("data-href"))#enname
#URLの保存
#urllib.request.urlretrieve("https://www.j-shiyaku.or.jp/pdf/public/sds/015/04349.pdf",'save.pdf' )
sheet.cell(row=Row, column=8).value=companys[compNo]
Row+=1
#print(" ")
continue
#break
#次ページがあrばクリック
if pageNo==1:
break
elif pageNo==2:
if nextButton[1].get_attribute("value")=="前の20件を表示":
break
nextButton[1].click()
elif pageNo==3:
nextButton[2].click()
def main(Pass):
global Row,companys,urlHead
start = time.time()
#keyの格納
#データの入出力用xlsxシートの定義
wb = openpyxl.load_workbook(Pass)
sheet = wb['Sheet1']
for r in sheet.iter_rows(min_row=Row, min_col=2, max_row=sheet.max_row, max_col=8):
for cell in r:
cell.fill = PatternFill(fill_type = None)
cell.value=None
i=2
keywords=[]
while True:
word=sheet.cell(row=i, column=1).value
if word is None or word =="":break
keywords.append(word)
i+=1
hitNo=0
#print(res.text) #全html参照可
res = requests.get(url)
soup = BeautifulSoup(res.text, "lxml")#lxmlが高速
elems = soup.find_all(href=re.compile("Sds/Search"))
#相対URLーー>絶対URl変換用。取得した各会社のurlの前半部分は省略されているので。
urlHead="https://www.j-shiyaku.or.jp"
#各会社のBeautifulSoupを生成
newUrl,newRes,newSoup=[],[],[]
for j in range(len(companys)):
for i in range(len(elems)):
if companys[j] in str(elems[i].contents[1]):
newUrl.append(urlHead + elems[i].attrs['href'])
newRes.append(requests.get(newUrl[-1]))
newSoup.append(BeautifulSoup(newRes[-1].text, "lxml"))#lxmlが高速
for key in keywords:
"""
ここでkeyの全角半角の変換などをしたいが、mojimojiのinstallが難。まぁしなくてもよい。
"""
#changeCompは再起関数。URL見つけるまで終わらない。第一引数はcompNo=0(初期値)
if not changeComp(0,key,newUrl,sheet):
#changeComp=False-->全ての会社で検索結果なし
print(key + " is NOT found.")
print(" ")
#Excel書き込み
sheet.cell(row=Row, column=2).value=key
sheet.cell(row=Row, column=3).value=0
Row+=1
continue
hitNo+=1
#print(hitNo)
print("!!All Done!!" + "\n")
wb.save(Pass)
wb.close()
elapsedTime = time.time() - start
print("elapsedTime= {0}".format(round(elapsedTime,2)) + " /sec")
if __name__=="__main__":
#保存したいURL先。フルパスでもOK
#Pass="/content/drive/MyDrive/Colab Notebooks/test.xlsx"
#Pass="template.xlsx"
#print("左ペイン> ファイル > drive > My Drive からファイル上で左クリックして フルパスをコピーし、")
Pass=input("フルパスを入力してください。:")
companys=["富士フイルム","関東化学","昭和"]
#日本試薬協会URL。ただ時々サイトの装丁が変更されているので注意が必要。
url = "https://www.j-shiyaku.or.jp/Sds"
cNo=0 #補正用。
#開始行
Row=2
main(Pass)
##jupyterもしくはGoogle Colabで実行したい場合##
今回1番困ったことですが、なぜかJupyter環境で実行すると、取得した配列データが1個ズレる。(どなたか理由を教えてください。)
どうしようもないので、補正値をつくってごまかしました。
最後、cNo=1に変更してからJupyter環境で実行してください。
あと、GoogleColabの場合は適宜コメントアウトを消してください。
##使い方##
①入出力用Excelファイル↓を適当なところに保存。
②"A2"セルから下方向に調べたい試薬を記入
③上書き保存して閉じる。
④ソースコード最終ブロックの、companys配列に調べてほしい会社名順に代入。何個でもよい。
⑤実行。フルパスを入力する。
こんな感じで、各試薬で検索してヒットした試薬(CAS.Noで重複は除いている。)を調べてきます。
URL欄をクリックすれば各試薬のSDSのPDFデータに飛びます。
以上!!