1. 개요

크롤링(Crawling) 이란? 

정식명칭은 Scraping 또는 Web Scraping 으로 웹 사이트에서 원하는 정보를 추출하는 것을 의미합니다. 보통 웹 사이트는 기본적으로 Html 기반입니다. 크롬에서 Ctrl + U 또는 우클릭 - 페이지 소스보기를 클릭하시면 다음과 같은 화면을 볼 수 있습니다.





네이버 금융 웹 사이트 소스코드


위 사진은 네이버 금융  https://finance.naver.com/ 홈페이지의 소소를 확인한 것입니다.



2. 활용

그렇다면 이 소스들을 가지고 우리는 무엇을 할 수 있을까요?

Html 소스들을 자세히 들여다 보시면 우리가 웹 사이트에서 보는 모든 정보들이 담겨있습니다.

이 정보들 중 원하는 정보만 가져와서 자신만의 프로그램에 사용하는 것 입니다.


불법아닙니까?

-> 크롤링 한 데이터를 소장하고 활용하는것 까지는 불법이 아닙니다. 다만, 영리를 위한 목적, 배포 시 문제가 될 수 있습니다. 후자의 경우 해당 사이트의 허락을 꼭 맡으시기 바랍니다.


예제로 네이버 금융 사이트에서 국제시장환율 란의 환율 데이터를 긁어와서 화면에 출력해 보겠습니다.




3. 소스코드





4. 실행화면





위 코드를 실행하면 다음과 같이 콘솔창에 크롤링 한 데이터가 출력됩니다.

프로그램에 따라 윈도우 창에 출력 할 수도 있고 변수에 저장하거나 데이터베이스에 저장 할 수 도 있겠습니다. 

사실 문자열을 조금만 다룰 줄 안다면 쉽게 처리 가능한 기술입니다. 





정보가 유익하셨다면 아래 공감버튼 눌러주시면 감사하겠습니다.

질문사항은 댓글로 달아주시면 성의껏 답변해드리겠습니다.



안드로이드로 카메라를 연동 및 제어 방법입니다.

소스코드는 주요소스코드만 첨부합니다.

설명은 주석을 참고하세요.



1. AndroidManifest.xml 에 접근 권한 추가


<!-- 카메라 권한 -->

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.CAMERA" />


2. SnackBar로 접근 권한 설정


// 카메라 접근 권한

private static final int PERMISSIONS_REQUEST_CODE = 100;

String[] REQUEST_PERMISSIONS = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};

private static final int CAMERA_FACING = Camera.CameraInfo.CAMERA_FACING_BACK;

private SurfaceView surfaceView; // 카메라 Preview 출력

private CameraPreview mCameraPreview; // 카메라 Preview

private View mLayout; // SnackBar 사용


// 화면 켜진 상태 유지

getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);


// 최초 카메라 Preview가 켜졌을 때

if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){

     int cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);

     int writeExternalStoragePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);


     // 권한 허용 시

     if(cameraPermission == PackageManager.PERMISSION_GRANTED && writeExternalStoragePermission ==                    PackageManager.PERMISSION_GRANTED){

          startCamera(); // 카메라 Preview를 SurfaceView에 출력

     }

            

     // 권한 없을 시            

     else{         

          if(ActivityCompat.shouldShowRequestPermissionRationale(this, REQUEST_PERMISSIONS[0]) ||     

               ActivityCompat.shouldShowRequestPermissionRationale(this, REQUEST_PERMISSIONS[1])){        

               Snackbar.make(mLayout, "이 앱을 실행하려면 카메라와 외부 저장소 접근 권한이 필요합니다.",                   

                    Snackbar.LENGTH_INDEFINITE).setAction("확인", new View.OnClickListener(){                   

                    @Override                   

                    public void onClick(View v) {                    

                       ActivityCompat.requestPermissions(CameraAcitivity.this, REQUEST_PERMISSIONS, PERMISSIONS_REQUEST_CODE);         

                    }                  

               }).show();            

          }             

          else{ // 사용자가 퍼미션 거부 한 적이 없는 경우 퍼미션 요청                  

               ActivityCompat.requestPermissions(this, REQUEST_PERMISSIONS, PERMISSIONS_REQUEST_CODE);         

          }         

     }      

} else{ // 카메라 미 지원시        

     final Snackbar snackbar = Snackbar.make(mLayout, "디바이스가 카메라를 지원하지 않습니다.", Snackbar.LENGTH_INDEFINITE);         

     snackbar.setAction("확인", new View.OnClickListener() {             

          @Override            

          public void onClick(View v) {                

               snackbar.dismiss();            

          }         

     });        

     snackbar.show();    

}



3. 카메라 플래시 제어


flash_btn = (Button)findViewById(R.id.flash_btn); // 플래시 버튼 이벤트        

flash_btn.setOnClickListener(new View.OnClickListener() {

     @Override

     public void onClick(View v) {

          flash_count++;

          if(flash_count > 1)

               flash_count = 0;

     

          if(flash_count==1) { // 플래시 켜기

               CameraPreview.params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);

               CameraPreview.mCamera.setParameters(CameraPreview.params);

               Toast.makeText(CameraAcitivity.this, "Camera Flash ON", Toast.LENGTH_SHORT).show();

          }

          else { // 플래시 끄기

               CameraPreview.params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);

               CameraPreview.mCamera.setParameters(CameraPreview.params);

               Toast.makeText(CameraAcitivity.this, "Camera Flash OFF", Toast.LENGTH_SHORT).show();

          }

     }

});


4. 화면에 사각형 그리기


class DrawOn extends View{ // 사각형 그리기

    public DrawOn(Context context){

        super(context);

    }


    @Override

    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);


        Paint pt = new Paint();

        pt.setColor(Color.GREEN);

        pt.setStrokeWidth(5);


        canvas.drawLine(100,350,100,400, pt);

        canvas.drawLine(100,350,200,350, pt);


        canvas.drawLine(520,350,620,350, pt);

        canvas.drawLine(620,350,620,400, pt);


        canvas.drawLine(100,600,100,650, pt);

        canvas.drawLine(100,650,200,650, pt);


        canvas.drawLine(520,650,620,650, pt);

        canvas.drawLine(620,650,620,600, pt);

    }

}


5. SurfaceHoder 인터페이스


@Override

public void surfaceCreated(SurfaceHolder holder) {

// SurfaceView 생성시 호출 : 카메라 프리뷰 화면 출력 및 크기 회전 설정

    try{

        mCamera = Camera.open(mCameraID);

    }

    catch (Exception e){

        Log.e(TAG, "Camera" + mCameraID + " is not availabe : " + e.getMessage());

    }


    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();

    Camera.getCameraInfo(mCameraID, cameraInfo);


    mCameraInfo = cameraInfo;

    mDisplayOrientation = mActivity.getWindowManager().getDefaultDisplay().getRotation();


    int orientation = calculatePreviewOrientation(mCameraInfo, mDisplayOrientation);

    mCamera.setDisplayOrientation(orientation);

    

    mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();

    requestLayout();


    params = mCamera.getParameters();


    List<String> focusModes = params.getSupportedFocusModes();

    if(focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)){

        params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);

        mCamera.setParameters(params);

    }


    try{

        mCamera.setPreviewDisplay(holder);

        mCamera.startPreview();

        Log.d(TAG, "CAMERA Preview Started");

    }

    catch (IOException e){

        Log.d(TAG, "Error setting camera preview" + e.getMessage());

    }

}


@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

// SurfaceView 의 크기가 변경될 때 호출

    if(mHolder.getSurface() == null){

        Log.d(TAG, "Preview surface does not exist");

        return;

    }


    try{    

        mCamera.stopPreview();

        Log.d(TAG, "Preview Stopped");

    }

    catch(Exception e) {

        Log.d(TAG, "Error stating camera preview : " + e.getMessage());

    }


    int orientation = calculatePreviewOrientation(mCameraInfo, mDisplayOrientation);

    mCamera.setDisplayOrientation(orientation);


    try{

        mCamera.setPreviewDisplay(mHolder);

        mCamera.startPreview();

        Log.d(TAG, "Camera preview started");

    }

    catch(Exception e){

        Log.d(TAG, "Error stating camrea preview : " + e.getMessage());

    }

}


@Override

public void surfaceDestroyed(SurfaceHolder holder) {

// SurfaceView 종료시 호출

    if(mCamera!=null){

        if(isPreview) 

            mCamera.stopPreview();

        mCamera.release();

        mCamera = null;

        isPreview = false;

    }

}


6. 이미지 저장하기


// 이미지 저장

private class SaveImageTask extends AsyncTask<byte[], Void, Void> {

@Override

protected Void doInBackground(byte[]... data) {

    FileOutputStream outStream = null;

    try {

        File path = new File (Environment.getExternalStorageDirectory().getAbsolutePath() + "/camtest");

        if (!path.exists()) {

            path.mkdirs();

        }

        String fileName = String.format("%d.jpg", System.currentTimeMillis());

        File outputFile = new File(path, fileName);


        outStream = new FileOutputStream(outputFile);

        outStream.write(data[0]);

        outStream.flush();

        outStream.close();


        Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length + " to " + outputFile.getAbsolutePath());

        mCamera.startPreview();

        // 갤러리에 반영

        Intent mediaScanIntent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

        mediaScanIntent.setData(Uri.fromFile(outputFile));

        getContext().sendBroadcast(mediaScanIntent);


        try {

            mCamera.setPreviewDisplay(mHolder);

            mCamera.startPreview();

            Log.d(TAG, "Camera preview started.");

        } catch (Exception e) {

            Log.d(TAG, "Error starting camera preview: " + e.getMessage());

        }

    } catch (FileNotFoundException e) {

        e.printStackTrace();

    } catch (IOException e) {

        e.printStackTrace();

    }

    return null;

    }

}



* 실행화면




다음번엔 제어한 카메라 화면과 Tesseract-OCR을 사용해 자동차 번호판 인식 어플리케이션을 제작해보겠습니다.


* 참고 글

SurfaceView 화면 캡쳐하기

Bitmap 이진화 처리






Android Studio에서 EditText 사용시 필요한 Methods에 대한 정리입니다.


1. ems : 최초 기본 너비 설정

사용 : android:ems="8"


2. maxLength : text 최대 길이 설정

사용 : android:maxLength="12"


3. textColor : text 색상 설정

사용 : android:textColor="#000000"


4. lines : 줄 개수 설정(최초 사이즈 확보)

사용 : android:lines=1


5. maxLines : 줄 최대 개수 설정(최초 사이즈1)

사용 : android:maxLines=2


6. singleLine : 한줄만 사용

사용 : android:singleLine="true"


7. background : 배경 설정

* 테두리있는 EditText 만들기

- xml파일 생성(layer-list)

- 다음과 같이 입력


<item>

<shape android:shape="rectangle">

<stroke android:width="1dp" android:color="FF948B8B"/>

<solid android:color="#FFFFFFFF"/>

</shape>

</item>


- 해당 파일을 editText에서 android:background="@drawble/파일명"으로 설정


8. capitialize : 자동 대문자 변경

사용 : android:capitialize="속성"

속성값 : 

characters - 모든 글자 대문자로 변경

words - 각 단어의 첫번째 글자를 대문자로 변경

sentences : 각 문장의 첫번째 단어를 대문자로 변경

none - 사용안함


9. hint : EditText가 비어있는 상태에서 출력 될 내용

사용 : android:hint="텍스트를 입력하세요."





InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); // 키보드 객체 받아오기


imm.hideSoftInputFromWindow(input_text.getWindowToken(), 0 ); // 키보드 숨기기


imm.showSoftInput(input_text, 0); // 키보드 보이기




InputMethodManager를 선언하고

키보드 입력 창을 보이고 싶은곳에 imm.showSoftInput을 입력

*parameter 1 : input_text 는 포커스를 받을 edit_text object 명

*parameter 2 : 0, HIDE_NOT_ALWAYS, HIDE_IMPLICIT_ONLY


키보드 입력 창을 숨기고 싶은 곳에 imm.hideSoftInputFromWindow를 입력

*parameter 1 : View.getWindowToken() : Request 받을 window token

*parameter 2 : flags : 0, HIDE_NOT_ALWAYS, HIDE_IMPLICIT_ONLY



[5과목 : 데이터 통신]

81. 맨체스터 코드

- 맨체스터 코드는 하나의 비트가 전송될 때, 각 비트타임 중앙에서 전압의 전이가 발생

- 아래는 맨체스터 코드의 예


82. HDLC(High-Level Data Link Control) 전송 모드

- NRM(표준 응답 모드) : 반이중 통신 p2p 또는 멀티 포인트 불균형 링크 구성

- ARM(비동기 응답 모드) : 전이중 통신 p2p 불균형 링크 구성

- ABM(비동기 균형 모드) : 전이중 통신 p2p 균형 링크 구성


83. 신호 속도

- 데이터 신호 속도(Bps) = 변조 속도(Baud) x 변조 시 상태 변화 수

- 1500(Baud) x 3(트리비트) = 4500(bps)


84. 자동 반복 요청(ARQ)

- Go-Back-N ARQ : 오류가 발생 한 이후 모든 블록을 재전송


85. IPv6

- IPv4의 주소 부족 문제를 해결하기 위해 128비트 개발


86. 패킷 교환 방식

- 패킷의 조립 및 분해 기능이 없는 비패킷형 단말기는 PAD(Packet Assembler / Disassembler)에 의해 패킷의 조립 및 분해


87. 전송 제어 문자

- NAK(Negative AcKnowledge) : 수신된 메시지에 대한 부정 응답

- ACK(ACKnowledge) : 수신된 메시지에 대한 긍정 응답

- EOT(End Of Transmission) : 전송 종료 및 링크 해제

- SOH(Start Of Heading) : 헤딩의 시작


88. 이더넷 시스템 규격

- 10 BASE T : 10 - 전송 속도(Mbps) / BASE : 베이스 밴드 방식 / T : 꼬임선(Twisted Pair Wire) 케이블 사용


89. IP(Internet Protocol)

- OSI 7계층의 네트워크 계층

- 데이터그램 기반 비연결형 서비스 제공

- 패킷의 분해/조립, 주소 지정, 경로 선택 기능 제공


90. 통신 프로토콜 기본 요소

- 구문(Syntax), 의미(Semantics), 시간(Timing)


91. 경로 설정 프로토콜

- OSPF : 홉 수에 제한 없이 대규모 네트워크에 많이 사용, 라우팅 정보 변화 시 모든 라우터에 알림


92. 전송 제어 절차

- 데이터 통신 회선 접속 → 데이터 링크 설정 → 정보 메시지 전송 → 데이터 링크 종결 → 데이터 통신 회선 절단


93. STMD(Statistical Time Division Multiplexing)

- 전송할 내용 없이 시분할이 할당되는 표준 시분할 다중화의 비효율성을 극복하기 위해 개발

- 데이터를 임시 저장하는 버퍼 메모리 사용


94. QPSK(Quadrature Phase Shift Keying)

- QPSK의 대역폭 효율은 약 2bps/Hz이다.


95. TCP(Transmission Control Protocol)

- OSI 7계층의 트랜스포트(전송) 계층에 해당


96. RIP(Routing Information Protocol)

- 소규모 네트워크에 효율적인 방법으로 홉수를 15로 제한


97. OSI 7계층

- 물리 계층(Physical Layer) : 전송 매체의 기계적, 지능적, 절차적 특성 정의

- 데이터 링크 계층(Data Link Layer) : 인접 시스템 간 효율적 정보 전송

- 네트워크 계층(Network Layer) : 네트워크 연결 설정, 유지, 해제

- 전송 계층(Transport Layer) : 종단 시스템 간 데이터 전송

- 세션 계층(Session Layer) : 송 수신 측 관련성 유지 및 대화 제어

- 표현 계층(Presentation Layer) : 응용 계층과 세션 계층을 맞게 변환

- 응용 계층(Application Layer) : 사용자 접근 서비스 제공


98. 신호 대 잡음 비

- 통신 용량 = 채널 대역폭 x log2(1+신호 대 잡음 비)

- 100K = 10K x log2(1+x)

- 10 = log2(1+x)

- 1+x = 2^10

- x = 1023


99. CSMA/CD(Carrier Sense Multiple Access / Collision Detection) 방식

- CSMA/CD 방식을 사용하는 LAN을 이더넷이라고 한다.


100. 패킷 교환 방식

- 일정한 길이의 패킷으로 잘라서 전송

- OSI 네트워크 계층

- 패킷 오버헤드 발생



2018.04.28 필기 기출 해설 - 1. 데이터 베이스

2018.04.28 필기 기출 해설 - 2. 전자 계산기 구조

2018.04.28 필기 기출 해설 - 3. 운영체제

2018.04.28 필기 기출 해설 - 4. 소프트웨어 공학



오타 및 질문사항은 댓글로 달아주세요!


to Top