이번에는 간단하게 긁어오기 쉬운 뉴스 사이트의 정보들을 긁어들여와서 저장하는 진행을 한다.
먼저, EditPlus가 아니라 많이들 쓰는 NotePad++를 쓰면 안 되냐는 생각이 들겠지만, NotePad++는 옆에 디렉터리가 바로 안나오니까 그냥 그것때문에 쓰는거다. 아무 편집기나 이용하면된다. 본인이 편한걸로. 참고로 EditPlus는 30일 쉐어웨어다.
XAMPP는 쉽게 서버단을 구축해서 작동시키기 위해 이용한다.
여기서는 Apache와 Mysql을 이용하기 위해 설치한다.
1. 검색 후에 이런 곳에 들어가면
2. 운영체제에 맞는 프로그램을 설치한다.
3. 설치프로그램을 누르고 따로 바꿀 사항없이
쭉 진행하면 다음의 화면을 얻게된다.
4. 이런 화면이 뜨면 그냥 기본으로 미국을 선택한다.
(독일어는 알아 들을 수 없는 나니까)
참고로 과정에서 뜨는 방화벽허용은
각 프로그램을 이용하기 위해 허락을 구하는 거니 허용하도록하자.
5. 프로그램이 실행하는 화면이다.
여기서 Apache랑 MySql을 이용 할 건데,
아래에 뜨는 오류 중 port오류가 발생한다면 ,
Apache는 [apache의 config - httpd-ssl.conf]에서 아래 부분을 다른 포트로 바꿔준다.
간단하게 442로 바꿔주면 될 것 같다.
그리고 나면 전체 config에 들어가서 포트부분 역시 변경해준다.
자, 이제 설정은 다 끝났다.
html과 php를 이용해서 뉴스에서 정보를 긁어오자!
아래는 ETNews 사이트의 정보를 긁어오는 소스다.
차근차근 뜯어서 살펴보자.
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
</head>
<body>
Crawling Test<br>
<form action="etnews.php" method="post">
<input type="text" name="sch_txt">
<input type="submit" name="search">
</form>
<?php
error_reporting(0);
include_once('simple_html_dom.php');
if(is_file('./output_data.txt')==true){
unlink('./output_data.txt');
}else{
echo "no file";
}
if(isset($_POST['sch_txt'])){
$conn = mysqli_connect("localhost", "root", "", "deu") or die("DB connect error");
mysqli_query($conn, 'set names utf8');
$truncate = "truncate article";
mysqli_query($conn, $truncate);
$sch_txt = $_POST['sch_txt'];
$sch_title = $_POST['sch_txt'];
$html = file_get_html("http://search.etnews.com/etnews/search.php?category=CATEGORY1&kwd={$sch_txt}&pageNum=1");
$reply_cnt = $html->find('h3.list_search_tit>span',0)->plaintext;
$num = preg_replace("/^0-9]*/s","",$reply_cnt);
$total_num = substr($num,5,6);
$file=fopen("./output_data.txt","a+");
for($j=1; $j<=10; $j++){
$html = file_get_html("http://search.etnews.com/etnews/search.php?category=CATEGORY1&kwd={$sch_txt}&pageNum=$j");
$i = 0;
foreach($html->find('dd.summury > a') as $element){
$i++;
$href = $element->href;
$url = file_get_html($href);
$title = $url->find('h2.article_title',0)->plaintext;
$title = trim(strip_tags(html_entity_decode($title, ENT_QUOTES)));
$title = str_replace("'", "", $title);
$title = str_replace("\"","",$title);
$contents = $url->find('section.article_body',0)->plaintext;
$contents = trim(strip_tags(html_entity_decode($contents, ENT_QUOTES)));
$contents = str_replace("'","",$contents);
$contents = str_replace("\"","",$contents);
$regdate = $url->find('time.date',0)->plaintext;
$d = substr($regdate, -2);
$m = substr($regdate, -5, -3);
$y = substr($regdate, -10, -6);
$rdate = $y."-".$m."-".$d;
$query = "insert into article set art_date=\"{rdate}\", article=\"{$contents}\", title=\"{$title}\", url=\"{$href}\" ";
$result = mysqli_query($conn, $query);
fwrite($file, $contents);
fwrite($file, "\r\n ");
}//foreach
}//for
echo "총".$total_num."건 기사 중";
echo $i."건 출력되었습니다.";
fclose($file);
}else{
echo "<p>검색어를 입력해주세요.</p>";
}//else
?>
</body>
</html>
| cs |
오른쪽의 화면은 전체 구성 화면이고 왼쪽의 화면은 아래의 소스가 구성할 화면이다.
1
2
3
4
5
|
Crawling Test<br> <!--Crawling Test라는 것을 알리고-->
<form action="etnews.php" method="post">
<input type="text" name="sch_txt"><!-- text를 통해 입력받은 정보를 sch_txt라는 변수로 넘기고-->
<input type="submit" name="search"><!-- 제출이라는 버튼을 누르면 etnews.php라는 파일이 post라는 동작으로 실행되겠다.-->
</form>
| cs |
이제 본격적으로 실행 될 php를 작성한다.
1
2
3
4
5
6
7
8
|
<?php
error_reporting(0);//에러 발생시 어떤 에러가 일어나는지 표시
include_once('simple_html_dom.php');//아래에서 쓰일 형식이 설정되어 있는 파일
//여기선 db저장 뿐만 아니라 파일로도 저장할 것이기 때문에 파일이 존재하는지 확인하고 있으면 unlink
if(is_file('./output_data.txt')==true){
unlink('./output_data.txt');
}else{//정상적인 동작을 할 때 실행
echo "no file";
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
if(isset($_POST['sch_txt'])){ //만약 위에서 검색창에 단어가 존재한다면
//DB연결을 시도. "localhost"라는 주소에 "root"사용자로 pw는 "", 데이터베이스명은 "deu"
$conn = mysqli_connect("localhost", "root", "", "deu") or die("DB connect error");
//혹시나 하니 utf8설정해주고
mysqli_query($conn, 'set names utf8');
//article이라는 테이블을 쓰겠다고 설정
$truncate = "truncate article";
mysqli_query($conn, $truncate);
$sch_txt = $_POST['sch_txt'];// $sch_txt변수는 검색창에 쓴 말(default설정)
$sch_title = $_POST['sch_txt'];// $sch_title변수는 검색창에 쓴 말(default설정)
//여기서 부터의 설명은 아래의 그림을 참고하자.
$html = file_get_html("http://search.etnews.com/etnews/search.php?category=CATEGORY1&kwd={$sch_txt}&pageNum=1");
$reply_cnt = $html->find('h3.list_search_tit>span',0)->plaintext;
$num = preg_replace("/^0-9]*/s","",$reply_cnt);
$total_num = substr($num,5,6);
$file=fopen("./output_data.txt","a+");//앞으로의 소스를 파일에 저장하기위해 open!
| cs |
먼저, 저 html을 어떻게 들고오게 된 것이냐면,
1. etnews.com에 접속
2. 왼쪽 상단의 검색창에서 단어를 검색
검색 하단의 "뉴스 더보기"를 클릭해서 검색된 전체기사를 본다.
그러면 아래와 같이 번호들이 뜨고
주소창을 보면,
http://search.etnews.com/etnews/search.php?category=CATEGORY1&kwd=인도&pageNum=1&pageSize=3&reSrchFlag=false&sort=1&startDate=&endDate=&sitegubun=&jisikgubun=&preKwd%5B0%5D=인도
와 같이 뜬다는 것을 알 수 있다.
페이지를 달리 해가면서 보면, 규칙이 존재한다.
1페이지, 2페이지,... 의 공통분모를 찾는거다.
http://search.etnews.com/etnews/search.php?category=CATEGORY1&kwd=인도&pageNum=2&pageSize=10&reSrchFlag=false&sort=1&startDate=&endDate=&sitegubun=&jisikgubun=&preKwd%5B0%5D=인도
어디가 바뀌고, 어디가 안 바뀌는지를 찾았으면
주소창에 쳐보면서 불필요한 부분들을 제거한다.
위의 예제에서는 긴주소를 다음과 같이 검색해도 동일한 결과를 얻는다.
http://search.etnews.com/etnews/search.php?category=CATEGORY1&kwd=인도&pageNum=1
규칙을 찾았다면 $html = file_get_html("여기")
"여기"부분에 입력해줄건데, 위의 keyword인 인도를 $sch_txt로 검색 할 부분이기 때문에 주소에서도 수정해준다.
그럼 다음과 같이 된다.
참고로 file_get_html이라는 함수는 위에서
include_once했던 'simple_html_dom.php'파일에 정의가 되어있다.
아래에서 쓰일 대부분의 parsing은 위의 파일을 이용해서 처리하고 있다.
$html = file_get_html("http://search.etnews.com/etnews/search.php?category=CATEGORY1&kwd={$sch_txt}&pageNum=1");
3. 총 들고 올 기사의 갯수를 알아보자.
저 부분에 마우스를 대고 오른쪽을 클릭하면
다음과 같이 뜨게 되는데 저 부분의 html을 보여준다.
저 부분을 들고오기 위해 다음과 같이 쓴다.
$reply_cnt = $html->find('h3.list_search_tit>span',0)->plaintext;
그러면 저 span안의 내용(( 18,852건 중11~20건 ))을 전부 들고오게 된다.
그러면 아래의 소스로 18,852라는 수만 남을 수 있게 수정해준다.
(참고로 수가 굉장히 커질때는 사람이 직접 다시 수정해줘야한다.
이 부분을 좀 더 유연하게 고칠 수 있다면 좀 더 나은 프로그램이 되겠지..)
//안에 들어가는 이상한 기호들을 ""으로 대체 $num = preg_replace("/^0-9]*/s","",$reply_cnt);
//그러게 걸러진 문장을 5번째부터 6개정도 자른다. $total_num = substr($num,5,6);
1
2
3
4
5
6
7
8
9
10
11
12
13
|
for($j=1; $j<=10; $j++){ //10개의 기사를 읽어들여오겠다고 제한.
// 만약 전체 기사를 끌고오고 싶다면? 10대신 $total_num을 넣자!
$html = file_get_html("http://search.etnews.com/etnews/search.php?category=CATEGORY1&kwd={$sch_txt}&pageNum=$j");
//위의 방법과 같은데 $j, 즉 페이지의 수가 추가되었다.
$i = 0; // 나중에 총 출력 건수를 표시해주기 위해 존재.
foreach($html->find('dd.summury > a') as $element){
//이 부분은 많은 페이지들이 존재하는 1페이지에서 각각의 url들을 끌고 오기 위한 방법.
//어떤 부분을 말하는거지? 싶으면 아래를 참조하자.
$i++;
$href = $element->href; //대부분 <a href ~>형식으로 되어 있어서 다음과 같이 처리!
$url = file_get_html($href);
//그 페이지로 이동! 참고로 url주소인 경우에 echo를 해버리면 그 사이트로 이동해버린다.
//echo $url;
$title = $url->find('h2.article_title',0)->plaintext;
$title = trim(strip_tags(html_entity_decode($title, ENT_QUOTES)));
//$title 필요한 부분만 잘라내준다.
$title = str_replace("'", "", $title);
//$title에서 '나 \"부분을 공백으로 대체
$title = str_replace("\"","",$title);
| cs |
다음과 같이 선택하면 dd.summary > a부분을 읽어와야한다는 사실을 알 수 있다.
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
|
//contents는 title과 같은 형식으로 필요한 부분을 들고오도록 설정
$contents = $url->find('section.article_body',0)->plaintext;
$contents = trim(strip_tags(html_entity_decode($contents, ENT_QUOTES)));
$contents = str_replace("'","",$contents);
$contents = str_replace("\"","",$contents);
//날짜부분은 기사 형식에 따라 다르다.
//대부분의 뉴스기사는 그냥 바로 넣으면 되는 형식이지만 다음과 같은 형식으로 바꿔준다.
$regdate = $url->find('time.date',0)->plaintext;
$d = substr($regdate, -2);
$m = substr($regdate, -5, -3);
$y = substr($regdate, -10, -6);
$rdate = $y."-".$m."-".$d;
//db에서 실행시킬 query문을 작성한다.
$query = "insert into article set art_date=\"{rdate}\", article=\"{$contents}\", title=\"{$title}\", url=\"{$href}\" ";
$result = mysqli_query($conn, $query);
//파일에 기사내용을 저장한다.
fwrite($file, $contents);
fwrite($file, "\r\n ");
}//foreach
}//for
//완료되고 나면 화면에 보이는 부분
echo "총".$total_num."건 기사 중";
echo $i."건 출력되었습니다.";
fclose($file);
}else{//아직 검색어가 입력되지 않았을 때 실행되는 부분
echo "<p>검색어를 입력해주세요.</p>";
}//else
?>
| cs |
다음과 같이 맞는 부분을 걸러서 가져온다.
다음은 날짜를 가져오는 부분이다.
마지막으로 뽑아야 되는 부분을 정리를 하자면,