728x90
반응형

맥북에서 crontab을 통해 주기적으로 실행을 시켜보고싶은게 생겨서

crontab을 등록하여 테스트를 해보았더니 잘 작동이 되지않아서 찾아보니

macOS에서는 crontab 보다는 LaunchAgents를 통해 crontab의 역할을 한다고 한다.

 

 

하고싶었던 작업은 매일 오전10시에 어떤 작업을 수행할 것

* crontab 이라면 아마 이렇게 crontab -e 로 등록해서 사용했을 것 같다. 

0 7 * * * cd 실행할위치 && 실행하고싶은 명령어

사용방법

앞서 말했든 macOS에서는 crontab 보다는 LaunchAgents를 권장하고 있고 해당 방법은 간단하다

 

1. .plist 파일 작성:
 ~/Library/LaunchAgents/${너가수행할이름}.plist라는 파일을 생성

2. plist 샘플
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>본인의프로젝트명</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/sh</string>
        <string>-c</string>
        <string>cd 실행할위치 && 실행할명령어</string>
    </array>
    
    <key>StartInterval</key>  //실행간격
    <integer>120</integer>    //120초 (2분)
</dict>
</plist>

3. 내가 만든 plist가 잘 작성되었는지 확인
plutil -lint ${너가수행할이름}.plist
정상적으로 잘 만들어졌으면 => ${너가수행할이름}.plist: OK

4. plist load 
launchctl load ~/Library/LaunchAgents/${너가수행할이름}.plist

5. 등록이 잘되었는지 확인
launchctl list | grep ${너가수행할이름}


6. 만약 등록을 취소하고싶다면
launchctl unload ~/Library/LaunchAgents/${너가수행할이름}.plist

 

테스트를 위해 2분마다 실행되도록 plist를 만들었다.

 

 

여기서 내가 했던 실수들

1. <string>cd 실행할위치 && 실행할명령어</string> 여기서 && 를 xml 문법에 맞게 &amp;로 바꿔줬어야 했다. 

2. 처음에는 yarn start라고 실행할 명령어를 썻는데 fail이 떨어졌다 그래서 Full Path 로 변경 :   /opt/homebrew/bin/yarn start 

 

실수들에 대해서 수정을 하니 테스트가 잘 돌아간다. 

그래서 처음 계획했던 매일 오전 10시에 돌아갈 수 있도록 

실행 부분을 변경해주었다. 

    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>10</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>

 

728x90
반응형
728x90
반응형

 

요즘 포켓몬 유나이트를 너무너무 재밌게 하고 있어서

그거와 관련된 조그만 프로젝트를 하면 좋을 것 같아서 고민중에 있다. 

 

일단 오늘은 포켓몬 유나이트의 참전 포켓몬을 크롤링해서 이미지들을 다운받는거 부터 시작하려고 한다.

 

크롤링(crawling) 혹은 스크레이핑(scraping)은 웹 페이지를 그대로 가져와서 거기서 데이터를 추출해 내는 행위다. 

소스는 python 으로 되어있고, 패키지는 파이썬에서 웹 브라우저 상호작용을 자동화하는 selenium 을 사용했다. 

 

일단 본인의 크롬버전을 확인하고

그 크롬버전에 맞는 크롬드라이버를 다운받아줘야한다. 

 

크롬 버전 확인방법은 오른쪽상단에 세개의 점 아이콘을 클릭 후, 도움말에서 chrome정보 보기를 클릭하면 확인이 가능하다.

크롬버전 확인

 

 

크롬드라이버는 https://chromedriver.chromium.org/downloads 여기서 다운이 가능하다. 

본인의 버전에 맞게 설치하면 된다.

 

1
2
3
4
5
6
7
8
9
10
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import urllib.request
import os
 
 
# 크롬 연결
driver = webdriver.Chrome(executable_path='본인이 다운받은 /chromedriver')
driver.get("https://www.google.co.kr/imghp?hl=ko")
cs

다운받은 크롬드라이버의 위치로 크롬을 연결시켜주고

find 에는 다운받을 포켓몬을 list 로 만든다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 가져올 포켓몬 정하기
find = ['이상해꽃''리자몽''피카츄''알로라''나인테일''푸크린''괴력몬''야도란''팬텀''마임맨''잠만보''앱솔''한카리아스''루카리오''암팰리스''개굴닌자','파이어로''에이스본''백솜모카''윽우지']
 
for key in find:
    # print(key)
    # 이미지 찾기
    elem = driver.find_element_by_name("q")
    # 기존 입력값 초기화 함수 실행
    clear_text(elem)
 
    # find에 넣어논 포켓몬 리스트를 검색어로 넣는다.
    elem.send_keys(key)
    # 엔터키 입력
    elem.send_keys(Keys.RETURN)
cs
1
2
3
4
5
 
def clear_text(element):
    # 검색어 길이를 찾고, 그 길이만큼 백스페이스를 날려준다.        
    length = len(element.get_attribute('value'))
    element.send_keys(length * Keys.BACKSPACE)
cs

중간에 한번 for문을 돌고 나서, 기존의 검색어가 아직 남아있기 때문에

그 검색어를 지워주기 위해서 clear_text 함수를 만들었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 이미지가 없을 때 까지 스크롤 끝까지 내려가는 법
    # 스크롤 할때 잠깐 시간적 여유주기
    SCROLL_PAUSE_TIME = 1.0
 
    # Get scroll height
    last_height = driver.execute_script("return document.body.scrollHeight")
 
    while True:
        # Scroll down to bottom
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
 
        # Wait to load page
        time.sleep(SCROLL_PAUSE_TIME)
 
        # Calculate new scroll height and compare with last scroll height
        new_height = driver.execute_script("return document.body.scrollHeight")
        if new_height == last_height:
            try:
                #css 에서 다음페이지에 해당하는 id를 클릭해준다. 
                driver.find_element_by_css_selector(".mye4qd").click()
            except:
                break
 
        last_height = new_height
     # 이미지가 없을 때 까지 스크롤 끝까지 내려가는 법
 
    # 다운받는 부분
    images = driver.find_elements_by_css_selector(".rg_i.Q4LuWd")
 
    count = 1
    for image in images:
        # 가져올 갯수 정하기
        if count < 40:
            try:
                    image.click()
                    time.sleep(2)
                    imgURL = driver.find_element_by_xpath("/html/body/div[2]/c-wiz/div[3]/div[2]/div[3]/div/div/div[3]/div[2]/c-wiz/div/div[1]/div[1]/div[2]/div[1]/a/img").get_attribute("src")
                    
                    path = "./images/"+key
                    # 폴더가 없으면 생성하기 
                    if not os.path.isdir(path):
                        os.mkdir(path)
                    # 생성한 폴더에 이미지 저장하기
                    urllib.request.urlretrieve(imgURL, "images/"+key+"/"+key+str(count) + ".jpg")
                    count = count + 1
            except:
                pass
 
driver.close
cs

 

나머지 코드는 별거 없고,

 

이미지를 클릭한다음, 그 이미지를 다운받는다.

다운받은 이미지는 각각의 이름으로 폴더를 만들고

그 폴더에 count 를 해서 파일이름으로 저장해준다. 

폴더별로 저장된 이미지

내일은 요 이미지들을 가지고 teachable machine 에 적용시켜 모델을 학습해볼거다. 

 

728x90
반응형
728x90
반응형

 

 

어제 공부했던 textrank 로 했을 때, 결과값이 만족스럽지 않아서 다른걸 찾아보기로 했다. 

결과값이 만족스럽지 않다는거는 단어 추출은 잘되는데, 연관된 단어일 경우 분리되서 나와서

하나의 단어로는 그렇게 데이터로써 큰 가치가 없었다.

예를 들면 내가 원하는거는 "성과 창출" 인데 실제로 textrank 를 돌려서 나온값은 "성과" "창출" 

각각의 단어로 나오니까 하나의 단어로는 데이터로써 효용가치가 별로 없었다.

 

그래서 다른 좋은게 있는지 찾아보던중 , NetworkX 를 발견했다.

실제로는 다른분들은 그래프 형식으로 결과값을 도출해서 많이 사용하시던데

 

내가 원하는건 연관단어들의 텍스트형식의 결과물이었다.

 

NetworkX는 네트워크분석을 기본으로 하고 있고

 

네트워크 분석은 개인과 집단들 간의 관계를 노드(Node)와 링크(Link)로써 모형화하여, 그것의 구조나, 확산 및 진화과정을 계량적으로 분석하는 방법이다. 개체 자체의 속성에 중점을 둔 기존의 통계적인 연구방법과는 달리, 개체간의 상호 관계에 초점을 맞춘 방법이다. 네트워크 분석은 화학, 생물, 물리, 정보공학, 사회학, 인문학 등 다양한 분야에서 응용되고 있는 용어만 조금씩 다를 뿐 기본 원리는 그래프 이론에서 출발 했다고 할 수 있다. 소셜 네트워크 분석(SNA, Social Network Analysis) 역시 적용하는 대상과 용어만 다를 뿐 기본적인 분석 방법은 동일하다.
(참조 : https://kdata.or.kr/info/info_04_view.html?field=&keyword=&type=techreport&page=1&dbnum=192961&mode=detail&type=techreport) 

 

튜토리얼 참고 :https://networkx.org/documentation/stable/tutorial.html

 

Tutorial — NetworkX 2.6.2 documentation

This guide can help you start working with NetworkX. Nodes The graph G can be grown in several ways. NetworkX includes many graph generator functions and facilities to read and write graphs in many formats. To get started though we’ll look at simple mani

networkx.org

 

 

궁극적으로 내가 해보고싶었던 거는 

각 기사 혹은 책 제목을 읽어와서

가져온 List 에서 가장 많은 연관성이 있는 단어 묶음들을 찾고싶었다.

 

첫번째로는 당연히, 모델을 학습할 샘플데이터가 필요하다.

이거는 뭐.. 그냥 단순이 책이나 기사 제목을 크롤링해와서 test.txt 에 담았다.

그래서 lines를 만들어 주고

 

words_list 를 만들고 거기에 lines를 넣어줬다.

 

그리고 words_list로 모델을 학습하기 전에

불용어( 실제로 그 모델에서 제외할 단어들 ) 을 stopwords.txt 에 미리 넣어놓고

 

연관성있는 단어쌍을 만들어준다.

혹시.. enumerate 내장함수를 모르면 아래 사이트에 잘 설명이 되어있다.

 

참조: https://www.daleseo.com/python-enumerate/

 

[파이썬] enumerate 내장 함수로 for 루프 돌리기

Engineering Blog by Dale Seo

www.daleseo.com

 

이제 이중으로 Loop를 돌리면서 단어의 연관성을 찾으면 된다.

for 문을 자세히 보면 아래와 같이 돌아가는걸 알 수 있다.

 

샘플.txt
for문 출력

그래서 이제 이걸 이중 for 문 안에서 비교하면서 

count 에 넣어주게 된다.

 

다 만들고 나서 Dataframe 에 넣고 

원하는 컬럼으로 정렬하면 원하는 결과를 얻을 수 있다.

 

표본이 많으면 많을수록 더 정확하고 깔끔한 데이터를 얻을 수 있다.

 

최종 결과값

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import pandas as pd
 
f= open('test.txt', encoding='UTF8')
lines = f.readlines()
# len(lines)
# print(len(lines))
 
lines
 
words_list=[]
 
for text in lines:
    words_list.append(text.strip())
 
print(words_list[1])
# 불용어처리
stopwords =[]
=open('stopwords.txt')
lines = f.readlines()
for line in lines:
    line = line.strip()
    stopwords.append(line)
f.close()
# 불용어 list 만들어 줌
print('불용어 사전 출력' ,stopwords)
 
 
#{}이거는 dictionary 기호이다.
count = {}
for line in words_list:
    words = list(set(line.split()))
 
    # print(words)
 
    for i,a in enumerate(words):
        for b in words[i+1:]:
            if b not in stopwords:
                if a>b:
                    count[b,a] = count.get((b,a),0+1
                else:
                    count[a,b] = count.get((a, b), 0+ 1
 
# print(count)
 
count.get(("a","b"),0)
# print(count)
df=pd.DataFrame.from_dict(count, orient='index')
df.head
# print(df.head)
 
list1=[]
for i in range(len(df)):
    list1.append([df.index[i][0], df.index[i][1], df[0][i]])
 
df2= pd.DataFrame(list1, columns=["word1","word2","freq"])
 
# print(df2)
 
df3=df2.sort_values(by=['freq'],ascending=False)
df3.head(10)
 
print(df3.head(10))
cs

 

 

참조: http://gahwan.com/python-%EC%97%B0%EA%B4%80%EC%96%B4-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B6%84%EC%84%9D-with-networkx-package/

728x90
반응형
728x90
반응형

 

원래는.. 리뷰들을 모아서 그 리뷰에 대한 긍정적인 부분/ 부정적인 부분을 추려서 프로젝트를 하려고 했다.

기존에 나와있는 긍/부정 감성분석은 리뷰의 평점에 따라 좋은평점에서 긍정적인 단어를 추리고

나쁜평점에서는 부정적인 단어를 추리는 방식이었는데 내가 하고있던거는 미리 긍/부정도 단어사전을 만들고

단어 사전을 통해 긍정/부정을 추출하는 방식이었다.

 

암튼, 그 긍/부정도에 대해서는 못하게되어 다른 아이디어를 찾고있던 중 ..

발견하게 된거는 krwordrank 이다. text에서 핵심 문장/단어를 추출하는 알고리즘이다.

WordRank 알고리즘은 구글의 PageRank 나 HITS 같은 Graph Ranking을 자연어처리에 적용한 알고리즘 이다.

이거를 한국어의 어절 개념을 적용한게 KR-WordRank 라고 보면된다. 

 

사용방법은 아주 간단하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from krwordrank.word import KRWordRank
from krwordrank.hangle import normalize
 
min_count = 5   # 단어의 최소 출현 빈도수 (그래프 생성 시)
max_length = 10 # 단어의 최대 길이
verbose =True
wordrank_extractor = KRWordRank(min_count, max_length , verbose)
 
beta = 0.85    # PageRank의 decaying factor beta
max_iter = 10
 
with open('test.txt''r'as f:
    texts = []
    for line in f:
        texts.append(line)
 
texts = [normalize(text,english=False , number=Truefor text in texts ]
keywords, rank, graph = wordrank_extractor.extract(texts, beta, max_iter)
 
for word, r in sorted(keywords.items(), key=lambda x:x[1], reverse=True)[:30]:
        print('%8s:\t%.4f' % (word, r))
 
from krwordrank.word import summarize_with_keywords
 
stopwords ={'제거','할','단어'}
keywords = summarize_with_keywords(texts, min_count=5, max_length=10,
    beta=0.85, max_iter=10, stopwords=stopwords, verbose=True)
keywords = summarize_with_keywords(texts) # with default arguments
print(keywords)
cs

 

일단 분석할 샘플이 필요하고

해당 부분에서 한줄씩 읽어서 

나는 texts 라는 list에 담아줬다.

 

그 이후에 summeraize_with_sentences 라는 핵심문장을 추출하는 기능을 가지고 있는 부분을 적용시켜주면

원하는 값을 얻을 수 있다.

추출 원리는 랭킹이 매겨진 단어들로 백터를 생성하고 코사인 유사도를 적용하여 입력된 문장의 백터가 키워드 백터와 유사한 것을

선택하는 원리이다. 

 

도중에 빼고싶은 단어가 있다면 stopwoards 에 넣어주면 된다. 

추출한 결과값은.. 생각보다 잘 나온거 같다.

 

이제 이걸통해서 어떤식으로 보여줘야할지가 관건인 것 같다.

728x90
반응형

+ Recent posts