HTML에서 원하는 부분만 골라내자~
Web을 돌아다니다 보면 특정한 부분의 목록만 얻고 싶은 경우가 있습니다.
예를 들어 신문 기사 싸이트의 기사 제목과 본문만 얻는 경우라던지, 그 기사의 url만 얻는다 던지 하는 경우와
혹은 어떤 특정한 html에서 이미지의 경로(url)만 필요하다던지요.
사실 script 언어를 사용해서 정규식을 이용하면 쉽게 뚝딱하고 만들 수 있습니다만,
매번 만드는 것이 귀찮아서 C#으로 범용적으로 사용할 수 있게 만들었습니다.
사용법은 (저에게는 쉽지만..) 좀 복잡합니다.
예를 들어 아래의 그림과 같이 네이버 만화에서 정글고 목록을 뽑아오게 만들고 싶다고 가정합니다.
그렇다면 제일 먼저 해야할 일이 page 넘버를 찾는 것입니다.
원래 정글고 url 은 http://comicmall.naver.com/webtoon.nhn?m=list&contentId=15640 이것이지만
위의 그림에서 2 page를 클릭하면 http://comicmall.naver.com/webtoon.nhn?m=list&contentId=15640&page=2 주소에 page=2와 같은 파라미터가 추가되는 것을 알 수 있습니다. 08년 5월 9일을 기준으로 정글고의 page는 20개까지 있네요.
그렇다면 프로그램을 실행하고 URL 입력부분을 아래와 같이 입력합니다.
여기서 주의하셔야 할 것이 page= 뒤의 붙는 숫자는 변화하는 것이기 때문에 {0}을 써주는 것입니다.
여러 페이지에 걸쳐서 (from ~ to ~) 목록을 뽑을 때는 반드시 {0} 이어야 합니다.
(단, 하나의 URL에서 목록을 뽑을 때는 고정된 URL만 넣으시면 됩니다.)
이제 찾으려고 하는 패턴을 만들어보겠습니다.
http://comicmall.naver.com/webtoon.nhn?m=list&contentId=15640 이 페이지에 소스를 보면
위의 그림과 같이 뽑고자 하는 정글고 만화의 제목과 그것의 링크 부분을 발견할 수 있습니다.
<a href="/webtoon.nhn?m=detail&contentId=15640&no=192&page=1" class="gray_a01">입시명문 사립 정글고등학교 187화 <고민상담></a>
여기서 우리가 뽑아야 할 부분은 <a href=" 다음의 문자열부터 "까지의 주소로 표현된 문자열과 class="gray_a01"> 다음의 문자열 부터 </a>까지의 제목으로 표현되는 문자열입니다.
이것을 C# 정규표현식을 사용하여 표현하면
<a href="(/webtoon.nhn\?m=detail&contentId=.*)" class="gray_a01">(.*)</a>
위와 같이 됩니다. 원하는 부분을 괄호를 사용하여 그룹핑을 반드시 해주셔야 합니다.
정규 표현식(Regular Expression)에 익숙지 않으신 분들을 위해 잠시 설명하자면
. 는 모든 문자열을 말하고
* 는 0개 이상의 반복을 말합니다.
? 는 나올 수도 있고 나오지 않을 수도 있다는 것을 말합니다.
그러나 문자열로서 ?를 사용하고 싶다면 위의 패턴처럼 반드시 역슬래시 \를 붙여서 \?와 같이 사용하여야 합니다.
() 는 괄호 안에 쌓인 문자열을 그룹으로 뽑겠다는 말입니다.
위의 그림처럼 Pattern 항목에 정규식을 입력하고, Parse 버튼을 누릅니다.
ListView에 찾은 패턴들이 주루륵 들어가게 되는데요.
0 번에는 입력한 정규식 패턴으로 찾은 문자열이 들어가게 되구요.
1 번부터는 정규식에서 ( ) 를 통해서 그룹으로 뽑은 것들이 그룹의 숫자만큼 열이 생겨서 항목이 채워지게 됩니다.
마지막으로 이 ListView의 항목들을 텍스트 파일로 Export 하는 작업인데요
위의 그림처럼 ExportPattern 항목에 {그룹번호}를 포함하여 문자열을 입력하시고 Export 버튼을 누르면
텍스트 파일 형태로 저장할 수 있습니다. (이 문자열은 정규식 패턴이 아니라 C#에서 사용하는 string format을 사용하시면 됩니다.)
{2} \t http://comicmall.naver.com{1}
위와 같이 사용하실 수도 있겠네요.
C# 문법에 익숙하시면 간단히 사용하실 수 있겠죠? ^^;;;
"프로그래밍 / 자작 프로그램" 분류의 다른 글
| [C#] Range select sliderbar(trackbar) 배포 (0) | 2008/12/16 |
| 스도쿠(Sudoku) 답을 찾아 주는 프로그램 (2) | 2008/11/13 |
| K-means 보다 월등한 Isodata Clustering 알고리즘 구현 (0) | 2008/08/06 |
| Parser : HTML에서 원하는 부분만 골라내자~ 버전 업데이트 (5) | 2008/06/19 |
| 태터툴즈용 Silverlight Tag Cloud를 만들었습니다~ (0) | 2008/06/09 |
| [ATL/COM] IEContextMenu - 1.0.0.5 버전 배포 (13) | 2008/06/02 |
| [ATL/COM] IEContextMenu - 1.0.0.4 버전 배포 (6) | 2008/03/07 |
| [ATL/COM] IEContextMenu - 1.0.0.3 버전 배포 (3) | 2008/03/03 |





Parser.zip
댓글을 달아 주세요
대단하십니다~ 이런 프로그램을 보면 저도 꼭 프로그래밍을 배워보고 싶네요.
좋은자료 감사합니다.
조금만 관심을 가지시면 쉽게 배우실 수 있습니다. ^^
한가지 여쭙겠습니다
html 에서 uri 가지고 오는부분은 어케해서 작동하게 만들었는데요
html 에서 email 형식으로 된것을 가지고 오려니 당췌 정규식을 어케해야할지
감이 안오더라고요 msdn 에있는 정규식이라고 나와있는게
@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
이건데 이거넣고 실행해봐도 이메일을 추출못하더라고요
고수님의 한줄답변을 기다립니다
제메신져는 creative9100@hotmail.com 입니다 메신져안하시더라도 답변은 좀 남겨주세요
메일로그인해서 답변주셨나 확인하겠습니다 ^^;;
@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
여기서 앞에 @"와 뒤에 "; 를 빼시면 됩니다.
위의 프로그램에서 http://chaoskcuf.com/137 를 URL 입력란에 넣고, \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* 를 pattern 입력란에 넣으면
creative9100@hotmail.com 를 찾아낼 수 있습니다.
그러나 주의할 것이
대개의 싸이트에서 이메일 수집은 불법입니다.
많은 도움이 되고있습니다 ^^;;
근데 한가지 더 여쭐게 있는데요 페이징하는 방법좀 설명해주세요 -_-;;
{0} 이것으로 페이지가끝까지 가면 다음페이지 넘어가는 로직을 모르겠습니다 -_-;;
그리고 이멜정규식을 소스에 넣고 실행하면 문자열에라가뜨던데 그 원인이 몬지 로그렜어요 ㅠ.ㅠ
님처럼 텍스트박스에 넣고 하면 되고요 ㅠ.ㅠ
한번만 더 도와주세요오
"{0} 이것으로 페이지가끝까지 가면 다음페이지 넘어가는 로직을 모르겠습니다 " => 저는 그냥 단순히 "1 page 다음은 2 page다" 라는 것을 가정해 두고 만들었습니다. {0}은 C#의 String Format에 사용하는 형식일 뿐입니다.
"이멜정규식을 소스에 넣고 실행하면 문자열에라가뜨던데 그 원인이 몬지 로그렜어요" => C# 소스를 직접 작성하신다면 @"\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; 를 사용하시면 됩니다. 문자열 에러의 원인은 '\\'(역슬래시) 때문입니다. 정규식에서 사용하는 역슬래시는 기본적으로 의미를 가지고 있는 문자열입니다. @를 사용하지 않으실경우는 반드시 "\\\\" 이렇게 두개를 사용하여야 합니다.
앞선 답변에 감사드립니다
죄송한데 한가지 질문을 더 드릴일이 있어요
텍스트화일을 읽어들였는데요
라인이 20만줄인데
예를 들어 10번째줄부터 20번째줄까지만 가져오려한다면
어떻게 해야할까요??
이게 계속 10씩 증가하는데 다 읽어들여서 해당위치값을 불러들이는
반복작업을 시키자니 뒤로갈수록 화일다 읽고 해당위치 가져오고하면
꽁수코딩이 답이 아니더라고요
고수님의 한줄 답변을 기다립니다
답변이 늦었습니다.
http://chaoskcuf.com/149 글에 따로 질문에 대한 답변을 했습니다.
c# 초보입니다 질문한가지 드리겠습니다 제가 임의의사이트에 접속하려고 아래와 같이 코딩하였습니다
http 방식의 접속인데요...
timer_i = 0;
timer1.Interval = 100;
timer1.Start();
HttpWebRequest s_log = (HttpWebRequest)WebRequest.Create(http://www.www.com); //으로접속하여
.
......기타등등...
......기타등등...
......하고
.
url_connect.Write(sendBuffes_login, 0, sendBuffes_login.Length); //이렇게 값을 던졌습니다
timer1.Stop();
.
.
.
private void timer1_Tick(object sender, EventArgs e)
{
txt_time_out.Text = timer_i.ToString();
timer_i++;
}
이렇게요....
그런데 플이 응답이 없고 먹통이 되길래 웹브라우져로 열어보니 역시나 한참있다가 페이지없음이
뜨더라 이거죠 그래서
응답이 없으면 타이머로 5초간시간재서 응답이 없으면 중단을 하려고 타이머코드를 추가했는데요
저게 폼자체가 먹통이 되어서 시간이 올라가는게 보이질 않습니다 ㅠ.ㅠ
타이머도 작동안하고요 먹통이 되어서요
5초지나도 timer1.Stop(); 까지 진행이 안되면 응답없는 사이트로 간주하여 작업을 중단해야하는데
말이죠 1분까이 먹통됬다 오류페이지 띄워주십니다ㅠ.ㅠ
답변을 기다립니다...
아참 그리고 현재작업이 먹통이되어 중단하려면 this.Dispose(); 이 명령어를 호출하게 하면되나요??
현재작업중단 처리도 제가 헤메는 부분입니다
어떤님께 여쭤봤더니...
->보통 쓰레드를 사용해서 해결하는데...
->파일 읽어 오는 부분을 별도의 쓰레드로 만들어서
->시작하면 다른 이벤트 받는데 지장없습니다.
음....쓰레드처리하라시는데 제가 초보라...
약간의 코드주석을 좀 달아서 답변주시면 대단히 감사하겠습니다
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.someuri.com");
request.Timeout = 5000;
WebResponse reponse = request.GetResponse();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
원하시는 것이 5초간 응답이 없을 경우 request를 처리하는 것이라면 위와 같이 간단히 Timeout 프로퍼티를 사용하면 될 것 같은데요? ^^
현재 작업이 진행중이라고 this.Dispose()를 부르면 this는 해당 Form이고 그 Form이 종료되어 버립니다.
부득이 에 올려주신 처리방법으로 처리를 하고 싶으시면
class Program
{
static HttpWebRequest _request = null;
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 5000;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
try
{
_request = (HttpWebRequest)WebRequest.Create("http://www.someuri.com");
//_request.Timeout = 5000;
_request.GetResponse();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_request.Abort();
}
}
_request 객체에 Abort 함수를 불러주시면 Request가 중지됩니다.