Extra Form
라이선스 MIT

안녕하세요?


작년에 humit 님과 네모 님의 도움으로 작성했던 그누보드(아미나) 자동 글 작성 스크립트를 보완하여,


일본기상협회(tenki.jp)의 우리나라 날씨를 파파고 SMT로 번역한 후


그누보드에 자동으로 게시글을 작성하는 스크립트를 작성했습니다.


이 글을 빌어 humit 님과 네모 님께 다시 한 번 진심으로 감사드립니다! :)



우선 이 스크립트는 어디까지나 연습용임을 감안해주시고 연습 용도로만 사용해주시기를 부탁드립니다 ㅠㅠ


제가 나중에 제대로 된 사이트를 오픈하게 되면


초기에 게시판이 너무 썰렁한 경우에 저작권법을 준수하는 범위 내에서 응용해서 사용하려고 하네요 ^^



그누보드 게시글 자동작성 함수와 관련해서는 도와주세요 게시판에 제가 올렸던 글을 참조하시면 됩니다.


https://studyforus.com/index.php?_filter=search&mid=help&search_target=title&search_keyword=%EC%9E%90%EB%8F%99&document_srl=274040


당시에 humit 님께서 SQL 인젝션 관련하여 보완하라고 조언해주신 부분을 수정했고

(제가 addslashes(trim())을 넣기는 했는데 humit 님께서 말씀하신대로 제대로 수정했는지는 모르겠습니다 ㅠㅠ)


아울러 특정 IP에서만 PHP 파일이 실행되도록 수정하여 조금이나마 보안성을 높였습니다.


그래도 불안하여 함부로 실행되지 않도록 파일명을 길게 작성했습니다.



<?php
define('_INDEX_', true);
if ($_SERVER['REMOTE_ADDR'] === '실행을 허용할 IP') {
include_once('./_common.php');
include_once("./simple_html_dom.php"); // Simple HTML DOM Parser를 필요로 합니다.
date_default_timezone_set("Asia/Seoul");

$url = "https://tenki.jp/world/5/89/47108/"; // tenki.jp의 우리나라 예보 URL
$ch = cURL_init();
cURL_setopt($ch, CURLOPT_URL, $url);
cURL_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = cURL_exec($ch);
cURL_close($ch);
$html = str_get_html($response);
 
function translation($skycondition) // 이하 파파고 SMT 번역기 함수
{
    $client_id = "파파고 SMT ID";
    $client_secret = "파파고 SMT PW";
    $encText = urlencode($skycondition);
    $postvars = "source=ja&target=ko&text=".$encText;
    $smturl = "https://openapi.naver.com/v1/language/translate";
    $is_post = true;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $smturl);
    curl_setopt($ch, CURLOPT_POST, $is_post);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch,CURLOPT_POSTFIELDS, $postvars);
    $headers = array();
    $headers[] = "X-Naver-Client-Id: ".$client_id;
    $headers[] = "X-Naver-Client-Secret: ".$client_secret;
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $response = curl_exec ($ch);
    $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close ($ch);
    preg_match('/ext...(.+)...src/', $response, $match);
    if ($match[1] == "세이이치 비") { // 유독 이 부분 번역이 매끄럽지 않으므로 수정해줍니다.
        $match[1] = "맑음 때때로 비";
    }
    if($status_code == 200) {
        return $match[1];
    } else {
        return "Error:".$response;
    }
}
 
$today_date = date("d"); // 이하 오늘의 날씨
$today = $html->find('table[class=world-forecast-entry-table]' ,0);
$today_sky = translation($today->find('img', 0)->title);
$today_tempmax = $html->find('td[class=high-temp]', 0)->plaintext;
$today_tempmin = $html->find('td[class=low-temp]', 0)->plaintext;
$contents = "<strong style='color:blue'>".$today_date." </strong>".$today->find('img', 0)." ".$today_sky. " ".$today_tempmax." / ".$today_tempmin."<br>";
 
$body = $html->find('table[class=forecast-point-week]', 0); // 이하 일주일 날씨 예보
$str_body = $body; // DOM tree를 문자열로 변경합니다.
preg_match_all('/([0-9]{1,2})日/', $str_body, $matches);
 
$sky = $html->find('td[class=weather-icon]');
$tempmax = $html->find('span[class=high-temp]');
$tempmin = $html->find('span[class=low-temp]');
 
$number = count($sky);
for ($n = 0; $n < $number; ++$n)
{
    $skycondition_kr = translation($sky[$n]->plaintext);
    $contents = $contents."<strong style='color:blue'>".$matches[1][$n]." </strong>".$sky[$n]->find('img', 0)." ".$skycondition_kr." ".$tempmax[$n]->plaintext." / ".$tempmin[$n]->plaintext."<br>";
}
 
$html->clear();
unset($html);

 
 
function board_write($bo_table, $subject, $contents, $mb_id) // 이하 자동 글 작성 함수
{
    global $g5;
 
    $mb = get_member($mb_id);  
    $write_table = "g5_write_{$bo_table}";
    $wr_num = get_next_num($write_table);
    $wr_reply = '';
    $ca_name = "";
    $html = "html1"; $secret=""; $mail = ""; // 태그를 사용하되 br 태그는 필요없으므로 html1로 지정했습니다.
    $wr_subject = addslashes(trim($subject));
    $wr_content = addslashes(trim($contents));
    $wr_link1 = "";
    $wr_link2 = "";
    $wr_email = "";
    $wr_name = addslashes($bo[bo_use_name] ? $mb[mb_name] : $mb[mb_nick]);
 
    $sql = " insert into $write_table
                     set wr_num = '$wr_num',
                     wr_reply = '$wr_reply',
                     wr_comment = 0,
                     ca_name = '$ca_name',
                     wr_option = '$html,$secret,$mail',
                     wr_subject = '$wr_subject',
                     wr_content = '$wr_content',
                     wr_link1 = '$wr_link1',
                     wr_link2 = '$wr_link2',
                     wr_link1_hit = 0,
                     wr_link2_hit = 0,
                     wr_hit = 0,
                     wr_good = 0,
                     wr_nogood = 0,
                     mb_id = '$mb_id',
                     wr_password = '',
                     wr_name = '$wr_name',
                     wr_email = '$wr_email',
                     wr_homepage = '',
                     wr_datetime = '".G5_TIME_YMDHIS."',
                     wr_last = '".G5_TIME_YMDHIS."',
                     wr_ip = '{$_SERVER['REMOTE_ADDR']}',
                     wr_1 = '',
                     wr_2 = '',
                     wr_3 = '',
                     wr_4 = '',
                     wr_5 = '',
                     wr_6 = '',
                     wr_7 = '',
                     wr_8 = '',
                     wr_9 = '',
                     wr_10 = '' ";
    sql_query($sql);
    $wr_id = sql_insert_id();
    sql_query(" update $write_table set wr_parent = '$wr_id' where wr_id = '$wr_id' ");
    sql_query(" insert into {$g5['board_new_table']} ( bo_table, wr_id, wr_parent, bn_datetime, mb_id ) values ( '{$bo_table}', '{$wr_id}', '{$wr_id}', '".G5_TIME_YMDHIS."', '$mb_id' ) ");
    sql_query("update {$g5['board_table']} set bo_count_write = bo_count_write + 1 where bo_table = '{$bo_table}'");
    return true;
}
 
$bo_table = "1234"; // 게시판 테이블을 입력합니다.
$mb_id = "guest01"; // 작성자 id를 입력합니다. id가 존재하지 않으면 공백으로 출력되는 문제가 발생합니다.
$subject = "기상예보 - ".$today_date."일 발표";
 
$result =  board_write($bo_table, $subject, $contents, $mb_id);
echo "Success!"; // 뭔가 밋밋해서 일종의 로그로 넣었습니다 ㅠㅠ
}
?>



이 스크립트를 브라우저에서 실행시킨 후에 게시글 목록을 확인하면 


다음과 같이 새 게시글이 작성된 것을 확인할 수 있습니다.





해당 게시글을 클릭하면 다음과 같은 내용의 기상예보가 포함되어 있음을 확인할 수 있습니다.




참고로 원래 tenki.jp의 화면은 다음과 같습니다.




보충 설명을 드리면 요새 Accuweather나 일본기상협회를 참고하시는 분들이 많이 계셔서 


이 사이트의 정보를 가져오는 것으로 연습을 했습니다.

(참고로 Accuweather의 우리나라 일기예보 API는 유료이고, 웹페이지는 동적 웹페이지입니다)


제가 일본어를 전혀 할 줄 몰라서 착각한 것인지는 몰라도 


아쉽게도 tenki.jp에서 우리나라 일기예보는 API로 제공하지 않더군요 ㅠㅠ


그래서 부득이 이 부분은 파싱을 할 수밖에 없었습니다.


사실 예전에 Simple HTML DOM Parser 연습을 위해 작성해본 스크립트라서 군더더기가 많아서 부끄럽네요 ㅜㅜ



그리고 네이버 파파고 API와 관련하여 말씀드리면 NMT와 SMT 두 종류가 있는데 


구글링 해보면 대체로 NMT가 더 성능이 뛰어나다고 써있고, 제가 생각하기에도 대부분의 경우에 그럴 것 같습니다.


그런데 제가 번역하려고 하는 일기예보 단어에 있어서만큼은 SMT가 보다 우리말에 근접한 번역을 하더군요.


다만 "세이이치 비"라는 한본어(?) 번역 결과가 나와서 부득이 이 부분은 "맑음 때때로 비"로 강제변경 해줬습니다.


사실 "맑고 때때로 비" 또는 "맑지만 때때로 비"가 논리상으로나 일상에서 사용되는 어휘로서 보다 적절하다고 생각되지만


"맑음 때때로 흐림", "맑음 때때로 눈" 등 유사한 단어의 번역이 그런 형식으로 되어서 부득이 그렇게 변역했습니다.



여담이고 어디까지나 제 추측이지만 네이버 포털에서 제공하는 번역기는 


아마도 NMT와 SMT 방식을 조합한 최상의 결과물을 보여주는 것으로 추측되네요.


PHP로 머신러닝을 하는 방법을 제가 알지도 못하고 아무래도 이 스크립트의 범위를 벗어나는 것 같아서


간단히 "세이이치 비"만 변경하도록 했지만 앞으로 제가 예상하지 못한 다른 한본어(?)가 튀어나올 수도 있겠네요 ㅠㅠ



뭔가 그누보드에 아주 조금 적응한 것 같은데 라이믹스로 갈아타려니 아쉬운 마음도 드네요 ㅜㅜ


허접한 스크립트와 설명 읽어주셔서 감사합니다!


그럼 편안한 저녁 되세요 ^-^


  • ?
    도토리묵 2018.11.17 00:55
    오! 이거 잘만 활용하면 XE에서도 사용할수 있겠네요.
    감사드립니다.
    근데 왜 No Más! 이신지 ㅋㅋㅋ?
    No more 이라는 뜻 아닌가요?
  • profile
    이니스프리 2018.11.17 03:48

    오늘은 어쩌다보니 회식이 너무 길어졌네요 ㅠㅠ (현재 서울은 불금입니다)

    스페인어 No Más는 영어로 No more 맞아요 ^^

    XE에 대해서는 제가 잘 모르지만 테이블 구조가 상당히 다를테니 많이 수정하셔야 될거에요.

    (제가 아직 XE나 라이믹스로 넘어가지 못한 이유 중 하나네요 ㅠㅠ)

    그럼 즐거운 금요일 되세요~!

  • ?
    도토리묵 2018.11.17 04:20
    이쯤되면 이니스프리님이 운영하는 사이트가 궁금해지는군요 ㅋㅋ
  • profile
    이니스프리 2018.11.17 04:27
    저는 고수가 아니라서요~! ^^
    내년에 좀 더 그럴듯한 사이트를 만들면 공개하겠습니다 :)

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
38 코드 파이선 셸에서 실행하면...? 3 제르엘 2018.07.22 628
37 코드 [Python] 모 정부기관 사이트 파싱 후 PC 통신처럼 열람하고 싶은 게시글 번호를 입력하면 내용을 보여주는 소스 (허접) 4 이니스프리 2018.09.14 755
36 코드 [오토핫키] 특정 사이트에 대한 ping 테스트 결과를 실행시간과 함께 로그 파일로 저장하는 스크립트 2 이니스프리 2018.09.22 2102
35 코드 [오토핫키] 구글 드라이브의 공유링크를 이미지 호스팅을 위한 다이렉트 링크로 바꿔주는 스크립트 10 file 이니스프리 2018.09.25 1778
34 코드 [PHP] 기상청 중기예보를 캐러셀로 보여주는 위젯 (매우 허접합니다 ㅠㅠ) 10 file 이니스프리 2018.09.28 756
33 코드 [오토핫키] 브라우저를 열어 지난번과 동일한 폴더에 MZK를 다운받고 압축을 네이티브로 해제하는 스크립트 file 이니스프리 2018.10.20 928
32 코드 [PHP] 기상청 RSS 시간별 예보 위젯 - cache 적용(?) 9 file 이니스프리 2018.10.28 1003
» 코드 [PHP] 그누보드 자동 게시글 작성 - 일본기상협회의 우리나라 날씨를 크롤링한 후 파파고로 번역하여 글 작성 4 file 이니스프리 2018.11.15 842
30 코드 [아미나] 게시글을 작성하면 ID와 IP로 필터링하여 자동으로 랜덤 댓글을 남기기 (+랜덤 포인트) 7 file 이니스프리 2018.11.18 813
29 코드 [Python] 텔레그램을 이용한 게시판 새 글 알림봇 7 이니스프리 2018.12.02 4029
28 코드 [PHP] 간단한 캐싱 클래스 3 title: 황금 서버 (30일)humit 2018.12.06 882
27 코드 [아미나] 출석 여부를 나타내는 메인화면 위젯 4 file 이니스프리 2018.12.15 811
26 코드 [아미나] 네이트 실시간 검색어 순위 위젯 (아미나 캐시 적용) 3 file 이니스프리 2018.12.18 1134
25 코드 [PHP] 이미지를 원하는 크기(원본비율 유지)로 리사이즈 하여 출력 (원본 이미지는 수정하지 않습니다) 6 이니스프리 2018.12.20 8016
24 코드 [JS] http를 https로 리디렉션! 3 Hanam09 2018.12.30 884
23 코드 [JS]클라이언트에서 Ip를 얻어보자 2 Hanam09 2019.01.21 807
22 코드 [Python] 선택한 파일을 Dropbox API를 이용하여 업로드하고 공유링크를 받아서 이미지 호스팅 용도로 URL을 변환하기 1 file 이니스프리 2019.07.02 1192
21 코드 [Python] Selenium을 이용하여 특정 element를 캡처하는 스크립트 2 file 이니스프리 2019.07.03 6170
20 코드 [PHP/Javascript] 아미나에 자동으로 게시글을 생성하고 Ajax로 전송하여 결과를 표시하기 2 file 이니스프리 2019.07.09 963
19 코드 [Python] 네이버 모바일 이미지 검색에서의 이미지 파일을 멀티스레드로 다운받고 1개의 파일로 병합 11 file 이니스프리 2019.07.12 1557
Board Pagination Prev 1 2 3 4 Next
/ 4