윈플

크롤링하는 웹 사이트 UI가 바뀔 때마다 업데이트 되는 ㅠㅠ


먼저 간단히 정규식 패턴을 적용할 수 있는 Firefox의 부가기능을 소개하겠습니다.

"HTML Regex Data Extractor"
: Firefox - 부가 기능 - 'Regex' 로 검색 후 설치

[ 사용법 ]

1. Alt + R 로 툴을 시작합니다.

2. 원하시는 웹 사이트로 이동 후에 Ctrl + U 또는 마우스 오른쪽 버튼을 누른뒤 페이지 소스 보기를 누릅니다.
   그리고 소스를 "Content" 안으로 복사를 합니다.

Google Play를 기준으로 진행하겠습니다.

3-1. "Pattern"에 간단하게 추천 앱들의 이름을 알아내는 패턴을 적어보겠습니다.

ex ) <a class="title" title="Umano: News Read to You" href="/store/apps/details?id=com.sothree.umano"> 
      위와 같은 형식에 'title' 클래스 안에 'title'에 들어있습니다.
      제 부족한 정규식 능력에 한번에 뽑기는 어렵습니다. 'title'을 포함하는 문장 전체를 뽑습니다.
      <a class="title" [^>]*>  : 'title' 클래스의 < ~ > 문장을 다 뽑는 정규식 입니다.


3-2. 위 패턴으로 뽑은 결과값을 다시 한번 패턴으로 분류하기 위해, "Result" 내용을 "Content"로 옮깁니다. 
      그리고 다시 한번 패턴으로 뽑습니다.

      title=.*"    : title= 다음 " 표시까지 글을 뽑는 정규식입니다.


4. 결과값을 살펴보겠습니다.

[0] : title="Umano: News Read to You"
[1] : title="WhosCall(후스콜) - 발신자식별 및 차단"
[2] : title="Space Colony"
[3] : title="Flipboard: 여러분의 소셜 뉴스 매거진"

이 정도면 충분히 코딩으로 title만 뽑아낼 수 있습니다.  



C# 에서 위에서 뽑은 정규식을 토대로 실제로 Title을 뽑겠습니다.

먼저 정리를 하자면, Title을 뽑기 위한 두 가지 패턴이 있었습니다.
1차 패턴 : <a class="title" [^>]*>
2차 패턴 :  title=.*"


// 해당 url의 html 소스를 가져오는 부분입니다.
string
url = "https://play.google.com/store/apps";

string html = GetResponse(url);

string strPatternOne = "<a class=\"title\"[^>]*>";
string strPatternTwo = "title=.*\"";


// Regex 와 
MatchCollection 를 이용해서 패턴으로 분류합니다.             

Regex regex = new Regex(strPatternOne);
MatchCollection mc = regex.Matches(html);

foreach (Match m in mc)
{
        
// 첫번째 패턴으로 뽑아낸 데이터를 저장합니다..
        arrPattern[count++] = m.ToString();
}

for (int i = 0; i < count; i++)
{ 
        // 한번 더 정규식으로 뽑아내기 
        string strTemp = System.Text.RegularExpressions.Regex.Match(arrPattern[i], strPatternTwo).ToString();
        arrPattern[i] = strTemp;
}


// 위에서 사용된 함수원형입니다.
public
static string GetResponse(string url)

{
            HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;
            HttpWebResponse response = (request.GetResponse() as HttpWebResponse);

            StreamReader reader = new StreamReader(response.GetResponseStream());
            return reader.ReadToEnd();
}


System.Text.RegularExpressions.Regex.Match( );  ||  MatchCollection 을 이용한 방법
: 두 개의 방법 모두 사용해봤습니다. 편하신 걸로 골라 쓰시면 됩니다.
System.Text.RegularExpressions.Regex.Matches() 도 물론 있습니다.


PS. 사실 정규식 규칙에 대해서도 적고 싶지만, 사용할 때마다 헷갈리는 부분이라....




Comment +4

  • 주대명 2016.10.25 05:28

    혹시 궁금한게 html 입력하면 자동으로 정규식 나오는 프로그램 없을까요?

  • 주대명 2016.10.25 14:20

    화이어폭스 플러그인은 처음 사용해보는데 지금 화면처럼 좌측메뉴는 왜 안나올까요?
    크롬은 직관적으로 그냥 나오던데

    • 파이어폭스 버전이 어떻게 되신가요??
      47.0.1~49.0.2 버전에서 확인했는데요해당 플러그인 설치하고 Alt+R누르면 정상동작 됩니다.
      플러그인 설치 유부를 한번 확인해보세요

옆에서 불편하게 품질 테스트를 하고 있는 걸 보고 만들기로 했습니다.


- 목적 
1. 웹브라우저(크롬,사파리,오페라,파폭,익스플로어 등) 들 중 하나를 선택
: 각 프로그램 명 알아내기, 외부 프로그램 실행

(1) 웹브라웢 프로그램 명 

explore = iexplore.exe
chrome = chrome.exe
firefox = firefox.exe
safari = safari.exe
opera = C:\\Program Files (x86)\\Opera\\opera.exe 
( opera의 경우 system안에 없어서 그런지 저렇게 적어줘야 된다. '\\' 잘 못 된게 아니라 \인 경우 \이 인식이 안된다.




(2) 외부 프로그램 실행

// 선억
const int WM_SYSCOMMAND = 274;
const int SC_MAXIMIZE = 61488;

// 외부 메시지 보내기
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);

// 외부 윈도우 찾기
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);


System.Diagnostics.Process IEProcess = new System.Diagnostics.Process();
IEProcess.StartInfo.FileName = "iexplore.exe";           // explore 파일 이름
IEProcess.StartInfo.Arguments = "http://winplz.tistory.com";      // URL 
IEProcess.Start();     // 프로그램 실행





2. URL이 적혀있는 .txt 파일을 읽어
: 파일처리, txt파일 한줄씩 읽기

FileStream fs = new FileStream("C:\\input.txt", FileMode.Open, FileAccess.Read);     // 파일스트림        StreamReader sr = new StreamReader(fs, System.Text.Encoding.Default);    // 스트림리더객체
string getCount = sr.ReadToEnd(); // 전체 읽기
int count = 0;     // 몇 줄인지를 저장할 
foreach (char c in getCount) // 전체 읽기
{
    // 줄바꿈부호가 있으면 count필드를 증가시킴
    count = c.Equals('\r') ? count + 1 : count;
}
count++;
sr.BaseStream.Position = 0;  // 시작점 가리키기
while (!sr.EndOfStream)
{
    string currentLine = sr.ReadLine();      // 한줄씩 읽습니다.
    url[idx] = currentLine;
    idx++; // 인덱스 증가.
}






3. 설정한 (시간)간격으로 해당 URL로 들어간다.
: Timer 사용하기, 웹브라우저 주소 변경하기

(1) Form.cs 에서 timer를 올리기

(2) timer 생성
timer1 = new System.Windows.Forms.Timer();

(3) 시간 간격 설정
timer1.Interval = 1000;  (1000 = 1초)

(4) 핸들러 연결하기
timer1.Tick += new EventHandler(Timer_Tick); ( 설정한 간격마다 Timer_Tick 라는 메서드를 실행 )

ex) public void Timer_Tick(object sender, EventArgs e)
     {
            
     }

(5) timer 실행

timer1.Enabled = true;




- 문제점 발생
: 설정한 시간을 간격삼아 외부 프로그램(웹브라우저)를 실행시키고, 해당 URL로 가는 건 인터넷 검색으로 쉽게 구현하였다.
하지만! 실행한 웹브라우저의 주소가 바꿔지지 않고 새로운 웹브라우저가 URL이 바껴서 실행

--> 해당 URL의 주소로 웹브라우저가 계속 실행. 

- 임시방편 해결책
: URL 웹브라우저를 실행시킬 때, 프로세스를 검사하여 해당 웹브라우저를 끄고 다시 실행시킨다.


** 외부 프로그램 종료

Process[] p = Process.GetProcessesByName("iexplore");
if (p.GetLength(0) > 0)
    p[0].Kill();

// 익스플로어를 찾아서 해당 프로세스 kill. 

--> 문제가 해결되는것 같았지만, 오페라의 경우 강제 종료된 경우, 아래 화면과 같은 메시지를 먼저 호출하여서 오페라에서는 원활한 테스트가 진행되지 않았다.




대충 이 정도 소스 및 + 검색(당신의 노력)이면 충분히 목표한 메크로를 구현가능하다.
물론 귀차니즘과 능력부족으로 목표에 100%만족하는 프로그램은 아니지만 이 정도로만으로도 상당한 시간 + 귀차니즘을 해결할 수 있을것 같다.


Comment +0


// WebView 는 WebBrower 이름입니다.
// URL은 url이 들어있는 string 형입니다. 편하신 방법으로 사용

WebView.Navigate(URL);   
               or
WebView.Navigate("http://www.naver.com");
  



[ WebBrower가 제공하는 기본 ]

WebView.GoBack();                           // 뒤로가기

WebView.GoForward();                      // 앞으로가기

WebView.GoHome();                          // (현재 사용자의) 홈페이지로 
                                                        // 익스플로우 인터넷 설정창의 홈페이지로 이동 



이 정도도로 간단한 웹브라우저를 만들 수 있습니다.
 
1. 프로젝트를 하나 만듭니다.

2. 그리고 폼을 디자인을 합니다. 
   
     2.1 URL을 입력하고, 버튼들을 놓을 수 있게 MenuStrip를 척
                                                                 (ToolStrip로 할 수 도있지만, 이미지 구하기 귀찮아서..)
     2.2 그리고 제공하는 WebBrowser를 척! -> 부모로 도킹하기 (자동)
     2.3 그리고 각 버튼들을 놓읍시다.

뒤로가기, 앞으로 가기, Home버튼이 있는 브라우저가 되었습니다.

3. 내부적으로 기능 구현하기
 

뷰가 로드되자 마자 

 webBrowser1.Navigate("www.naver.com"); 

각 버튼들 클릭했을 때

            webBrowser1.GoBack();
            webBrowser1.GoForward();
            webBrowser1.GoHome();

그리고  웹브라우저의 이벤트 중에 DocumentCompleted (로드가 다 끝났을 때)
현재 웹브라우저의 url을 textbox로 옮기면 기본적인게 끝납니다.

              textBox1.Text = webBrowser1.Url.ToString();

 



너무 간단합니다.

다음엔 웹브라우저를 통해서 xml or html을 살펴보겠습니다.

Comment +0

클래스는 객체를 사용하기 위한 틀.


[순서]
1. 클래스 정의
2. 클래스 생성 및 사용
3. 멤버함수 알아보기
4. 생성자, 소멸자

위 순서대로 진행하겠습니다.



1. 클래스 정의

이름과 키, 몸무게를 멤버변수로 가지고 있으며,
이름을 출력하는 멤버함수를 가지고 있는 '사람' 이라는 클래스를 정의하겠습니다.


class People
{
public:                                                       // 접근권한 설정 ( 정보은닉, 캡슐화 )
                                                                // public : 모두 허용 ( 접근 범위 제한 X )
                                                                // private, protected : 접근 범위 제한 O ( 자세한 설명은 나중에 따로 )
   
// 멤버변수
    string P_name;
    float P_tall;
    float P_weight;


    // 멤버함수
    void PrintOfName()
    {
         cout << "이름 : " << P_name << endl;
    }

};                                                // 반드시 class 선언 뒤에는 세미 클론(;)




2. 클래스의 생성 및 사용


int main()
{
           // 객체 생성
           // People 이라는 클래스(틀)로 One, Two라는 객체를 생성했다.


           People One, Two;
           
          // 객체 초기화하기. ( 다른 방법도 존재.. 생성자에서 다루겠습니다.)
          One.P_name = "한놈";
          One.P_tall = 180.4;
          One.P_weight = 68.5;

          // 멤버함수를 사용하여 출력
          One.PrintOfName();

          return 0;
}




3. 멤버함수 알아보기

: 멤버함수는 기본적으로 일반함수와 같지만 약간은 다르다. ( 클래스의 멤버이기 떄문에...)

1. 멤버함수를 호출하려면 객체의 이름을 명시해야한다.
2. 멤버함수 안에서는 객체의 이름을 명시하지 않아도 접근이 가능하다.
3. 멤버함수 안에서는 외부에서 접근을 거부한 멤버에도 접근이 가능하다.
( 외부에서는 볼 수 없는 멤버도 안에서는 볼 수 있다는 의미.  ---- 접근 제어와 관련 나중에 더! )


멤버함수를 선언하는 방식.
( 2번째 방식이 좀 더 깔끔하다. )
첫번째 방식
 
class People
{
public:                                                       
    
// 멤버변수
    .
    .
    .
    // 멤버함수
    void PrintOfName()
    {
         cout << "이름 : " << P_name << endl;
    }

};       


 
2번째 방식

class People
{
public:                                                       
    
// 멤버변수
    .
    .
    .
    // 멤버함수
    void PrintOfName();
};       
 
// 클래스명 :: 멤버함수명
void People::PrintOfName();
{
         cout << "이름 : " << P_name << endl;
}
  


4. 생성자, 소멸자 

생성자와 소멸자는 특별한 멤버 함수라고 생각하시면 됩니다.

생성자 : 객체 생성 시 자동으로 호출되는 함수.
소멸자 : 객체 소멸 시 자동으로 호출되는 함수.

-> 생성자 : 준비 , 소멸자 : 정리
: 동작할 수 있게 준비, 다 사용한 뒤 정리. 


생성자는 인자가 있냐 없냐로 구분합니다. ( 디폴트 생성자, 인자가 있는 생성자 )


class People
{
public:                                                       
    
// 멤버변수
    .
    .
    .
    // 멤버함수
    ...
    //생서자들
    //클래스명과 동일, 반환값이 없다.

    People();
    People(string name, float tall, float weight);  
 
};        

People::People()
{
     P_name="";
     P_tall = 0.0;
     P_weight = 0.0;


People::People (string name, float tall, float weight)
{
     P_name=name;
     P_tall = tall;
     P_weight = weight;
int main()
{
           // 객체 생성
           
People One;
           
          // 객체 초기화하기(직접)
          One.P_name = "한놈";
          One.P_tall = 180.4;
          One.P_weight = 68.5;

           // 객체 초기화하기(자동 - 디폴트 생성자).  
          People Two;          

           // 객체 초기화하기(인자가 있는 생성자)  
          People Three("세번째",160.5,55.4);

          return 0;



각 각 출력을 하면 

One은 직접 입력한데로
Two는 디폴트 생성자가 모두 0으로 초기화 했으므로 0
Three는 집어넣은 인자로 출력됩니다.


 
 


생성자를 사용해 초기화하거나 생성하면서 바로 집어넣는 방법도 사용 가능합니다.
그렇다면 위와 같이 사용하지 않을 때는 생성자가 필요없다?
보통 그렇지만, 꼭 생성자가 필요한 경우가 존재합니다.

const 속성을 가진 변수와 레퍼런스 변수를 가지고 있을 경우.
( 이 경우 반드시 변수들이 초기화가 되어있어야 하기 때문에 반드시 생성자로 생성시 자동으로 초기화를 해주어야 합니다. )


소멸자는 생성자의 이름 앞에 ~를 붙인 형태.
오직 하나만 존재 가능. 


별거 없는 클래스.

Comment +2

C++ 표준 라이브러리에서 제공하는 스마트포인터.

: 참조되는 만큼 참조 카운트를 증가시키고, 반대라면 감소시켜 0이 되면 삭제 시키는 포인터라고 보면 되겠습니다.
( Objective-C에서 Auto-release or ARC 기능과 마찬가지로 어떻게 보면 사용하기 편한 포인터입니다. )

다음과 같은 3가지 특징이 있습니다.
1. 생성과 소멸 작업을 조절 가능.
2. 복사와 대입 동작을 조절 가능 .
3. 역참조 동작을 조절 가능.

하지만 타입제약이 엄격하다는 단점이 있습니다.

대표적인 스마트 포인터로는 auto_ptrshared_ptr 가 있습니다.
( 그 외에 weak_ptr, intrusive_ptr. shared_array, scoped_ptr 등이 있습니다. )
 
더 자세하게 알고싶다면  http://blog.daum.net/creazier/15309389  <-- 자세한 설명이 되어 있습니다!

아래는 위 블로그에서 일부분을 쓴 내용입니다.

1. auto_ptr    

    : C++ 표준 라이브러리에서 제공    
    : 
소유권 이전 금지 (-const 키워드 사용)  

    [특징]

    - 댕글링 포인터 문제를 해결한다.
     
: 이미 메모리에서 해체된 대상을 가리키고 있는 포인터 )


2. shared_ptr

    : 소유권이 공유되는 방식으로 동작하는 스마트 포인터    

    : STL 컨테이너에서 사용이 가능하다. (boost library를 반드시 설치하고, include 해야 한다.) 

    [특징]

    : 강한 참조의 성격을 가지고 있다.

    : Thread Safety 해제 - 헤더 파일에 " #define BOOST_DISABLE_THREADS "를 적어준다.



// 추가 설명 및 예제가 있는 블로그들... 
http://blog.daum.net/creazier/15309389  
http://blog.naver.com/kjs077?Redirect=Log&logNo=10106740255 

Comment +0