LostCatBox

whereMyPost

Word count: 1.5kReading time: 9 min
2019/01/08 Share

whereMyPost

만든이유

  • 택배를 조회할 때 우리는 항상 네이버, 다음, 해당 택배 홈페이지를 들어가서 번호를 입력하게된다

    이것을 카카오톡api를 사용하여 플러스 친구로 만들어 놓는다면 얼마나 편할까?

구현할 기능(중요도 순)

  • 택배사 선택후 운송장 번호 입력하면 택배 정보가 뜨는 (url로 안내함 or return값 전부 보여주던가)

  • 사용자가 조회 한번 햇던 운송장 번호와 택배사를 저장해놓고 바로 다시조회할수있도록구현

  • 조회번호 ‘-‘상관없이 그냥 다 number로 받아드릴수있게 구현하자

    (택배는 )

    python requests session 에서 _csrf값 가져오기

  • api로 연결후 json 응답받아야함.

  • 카카오채널에 최근 검색기록으로 바로 가져와서 클릭시 가져옴

  • 나중에 참고하기

  • 응답없거나 잘못된 송장번호일경우 따로 알려주기

  • 크롤링 참고 (https://beomi.github.io/2017/01/20/HowToMakeWebCrawler-With-Login/)

  • 배포 연습

  • AWS 서버 구성

  • DNS, 프로토콜, ssh, zsh,

  • Requests 라이브러리 쓰는거 꼭 자세히 알기

  • 세션 쿠키 개념 웹

    https://github.com/iBluemind/armatis

Realize

각 택배사 api사용(실패)

cj대한통운 을 기준으로 input한 데이터들을 처리하는 방식을 분석하고 똑같이

localhost:8000에서 구현시도

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
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>whereMyPost</title>
</head>
<body>

<div class="number-box">
<input type="text" id="paramInvcNo" name="paramInvcNo" value="운송장 번호 입력해주세요" style="width:353px;" maxlength="12">
<input type="submit" id="btnSubmit" title="Search">
</div>
"363219681522"
{{ post }}

<script
src="https://code.jquery.com/jquery-1.12.4.js"
integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU="
crossorigin="anonymous"></script>
<script src="https://www.cjlogistics.com/static/pc/global/template/js/jquery-migrate-1.4.1.min.js"></script>
<script src="https://www.cjlogistics.com/static/pc/global/template/js/front.js?v=2020010811"></script>
<script src="https://www.cjlogistics.com/static/pc/global/template/js/string.js"></script>
<script src="https://www.cjlogistics.com/static/pc/global/template/js/common.js?v=2020010811"></script>

<!-- //공통 : js -->
<script type="text/javascript">
var GLOBAL_SESSION_ID = "anonymousUser";
var GLOBAL_CSRF_NAME = "_csrf";
var GLOBAL_CSRF_VALUE = "1d119052-7262-401c-8fec-9f102beca2cb";
var GLOBAL_UPLOAD_URL = "/cjlwupload/";
var GLOBAL_DOMAIN_KOREAN = "";
var GLOBAL_DOMAIN_ENGLISH = "";
</script>

</body>


<script>
$('#btnSubmit').on('click', function (e) {
fncValidate();
});


function fncValidate() {
var paramInvcNo = $('#paramInvcNo').val();
console.log(paramInvcNo)


$.ajax({
url: 'https://www.cjlogistics.com/ko/tool/parcel/tracking-detail',
type: 'GET',
dataType: 'jsonp',
data: GLOBAL_CSRF_NAME + '=' + GLOBAL_CSRF_VALUE + '&paramInvcNo=' + paramInvcNo,
timeout: 1000,
async: false,

})
.done(function (json) {
console.log(json)
})
.fail(function (xhr, status, error) {
console.log(error)
})
.always(function (xhr, status) {
console.log("요청은 완료됨")

});
};

오류 발생

1
tracking-detail:1 Failed to load resource: the server responded with a status of 405 (Method Not Allowed)

실패 원인

  • CORS (???)

    ajax로 요청시 같은 도메인이 아닐시 거부됨

    이를 해결하기 위해 json대신 jsonp의 형식을 지원해줘야하는데

    이는 오픈해주시는 api 가 지원안해주시면 소용없다. (???)

  • 오픈api가 아니면 현재 실력으로 뚫기 어렵다고 판단.

Crawling으로 구현(1차 시도)

설치 및 기본 요령(블로그참조)

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
# 뷰에 쓰는 크롤링함수 모았음
from selenium import webdriver
from selenium.webdriver.support.select import Select
from bs4 import BeautifulSoup

driver = webdriver.Chrome('../chromedriver')
driver.implicitly_wait(15)
driver.get('https://search.naver.com/search.naver?sm=top_hty&fbm=1&ie=utf8&query=%ED%83%9D%EB%B0%B0%EC%A1%B0%ED%9A%8C')


#select클래스를 이용하여 쉽게 요소들중에서 찾을수있다.
select = Select(driver.find_element_by_class_name('_select'))

# select by visible text
select.select_by_visible_text('CJ대한통운')

# select by value
driver.find_element_by_id('numb').send_keys('349159576510')

driver.find_element_by_xpath('//*[@id="_doorToDoor"]/div[1]/div[2]/input[2]').click()

html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
post_detail = soup.select('#_doorToDoor > div._output > div.artb > table > tbody > tr')


post_list = []

for x in post_detail:
post_list.append(x.text.strip())

print(post_list)

실패 원인

자동화 프로그램을 네이버가 걸려서 애초에 조회가 불가능하게만듬,

Crawling으로 구현(2차 시도)

각 택배사 홈페이지에 따라 크롤링하는 방법을 선택

CJ대한통운

home.html에서 조회

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>

<form action = '{% url 'post:index' %}' accept-charset="utf-8" name = "post_infor" method = "get">
<fieldset style = "width:150">
<legend>택배 조회</legend>
회사 : <select name="post_company">
<option value="CJ대한통운"> CJ대한통운 </option>

</select>

운송장번호 : <input type = "text" name = "post_number"/><br><br>
<input type = "submit" value = "조회"/>

</form>
</body>

index.html에서 결과 표시

1
2
3
4
<form action = '{% url 'post:home' %}' accept-charset="utf-8" name = "post_backtohome" method = "get">
<input type = "submit" value = "돌아가기"/>

</form>

뷰에서 쓸 크롤링 함수를 따로 utils.py로 뺏다

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
from selenium import webdriver
from bs4 import BeautifulSoup


def postview(post_company='CJ대한통운', post_number='349159576510'):

if post_company == 'CJ대한통운':

driver = webdriver.Chrome('/Users/lostcatbox/myproject/whereMyPost/chromedriver')
driver.implicitly_wait(15)
driver.get('https://www.cjlogistics.com/ko/tool/parcel/tracking')


driver.find_element_by_id('paramInvcNo').send_keys(post_number)

driver.find_element_by_xpath('//*[@id="btnSubmit"]').click()

html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
post_detail = soup.select('#statusDetail > tr')


post_list = []

for x in post_detail:
post_list.append(x.text.strip())

driver.close()

print(post_list)
return post_list

Views.py 구성을 단순하게(앞에 함수를 호출만함으로 간단해짐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.shortcuts import render
from .utils import postview

def index(request):
post_company = request.GET['post_company']
post_number = request.GET['post_number']
data = postview(post_company, post_number)


return render(request, 'post/index.html', {'post':'고양이', 'post_list':data})
# Create your views here.

def homepage(request):

return render(request, 'post/home.html')

urls.py 생김새

1
2
3
4
5
6
7
8
9
from django.urls import path, include
from . import views
from . import utils

app_name='post'
urlpatterns = [
path('result/', views.index, name='index'),
path('', views.homepage, name='home'),
]

CU 택배조회

오류

크롤링 도중 html selector copy를 해도 return 값이 없었다.

이유는 아래와 같이 택배조회의 결과값이 iframe을 통해 보여주는 것이였다.

<iframe src=”#” width=”100%” height=”500” scrolling=”no” frameborder=”0” title=”배송상태” class=”mt20”></iframe>

따라서 selenium이 제대로 html을 받아오지 못하였다.

해결

iframe안에 html있다고 생각하면 편합니다. 즉, iframe html안에 들어가야 크롤링이가능합니다.

driver.page_source로 selenium이 현재 가져온 정보를 일일히 확인하면서 찾아본 결과 아래와 같이 코드를 짜면 원하는대로 크롤링 가능하였다.

1
2
3
4
5
6
7
8
# iframe태그가  한개면 리스트 반환이 아니므로 바로 써도됨, 여러개면 리스트로 반환되므로 순서도알아야함
iframe = driver.find_elements_by_tag_name('iframe')

driver.switch_to.frame(iframe[0])

html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
post_detail = soup.select(<원하는위치>)

+ tip: 원래있던 전체 웹 페이지로 나오려면 switch_to_default_content() 함수로 빠저나와야 합니다.

모든 택배회사가 위에 2사례로 모두 해결가능하엿다

추후 DHL홈페이지를 반드시 뚫어봐야겠다..

카카오 API 기본편 공부중…

비니지스 계정으로 전환하는 사유를 잘못보내서 6일넘게 소요되어버렸다,,ㅠㅠ

1
2
3
4
5
6
7
8
9
10
11
12



## 카카오 채널의 한계점

- 5초 이내로 답변하지 않으면 응답오류가 뜸>>따라서 크롤링으로 데이터를 던저주는것은 너무 힘듬 >>> 각 택배사별로 api를 따와서 해야할듯



# 크롤링포기>api로 전환

## 회사별 api 정보 가져오기

import

import requests

url

url = “http://hacksg.tistory.com"

get

r = requests.get(url, params={‘id’: ‘ksg’, ‘pw’: ‘password!@#’})

print r.status

print r.text

post

r = requests.post(url, data={‘id’: ‘ksg’, ‘pw’: ‘password!@#’})

print r.stats

print r.text




# AWS beanstalk으로 배포완료

## 배포 중 문제점들

### 오류: .gitignore를 쓰면...

aws 인스턴스의 ip 주소값을 공유하지 않기위해 이것을 secrets.json파일로 따로 다루고 .gitignore에 등록해놨더니, 값은 제대로 읽지만 막상 서버에올릴때도 이 파일이 무시되어 올라가므로 wsgi.py관련 오류가 뜬다.,..

#### 해결




CATALOG
  1. 1. whereMyPost
    1. 1.1. 만든이유
    2. 1.2. 구현할 기능(중요도 순)
  2. 2. Realize
    1. 2.1. 각 택배사 api사용(실패)
      1. 2.1.1. 오류 발생
      2. 2.1.2. 실패 원인
    2. 2.2. Crawling으로 구현(1차 시도)
      1. 2.2.1. 설치 및 기본 요령(블로그참조)
      2. 2.2.2. 실패 원인
    3. 2.3. Crawling으로 구현(2차 시도)
      1. 2.3.1. CJ대한통운
      2. 2.3.2. CU 택배조회
        1. 2.3.2.1. 오류
        2. 2.3.2.2. 해결
      3. 2.3.3. 모든 택배회사가 위에 2사례로 모두 해결가능하엿다
      4. 2.3.4. 추후 DHL홈페이지를 반드시 뚫어봐야겠다..
    4. 2.4. 카카오 API 기본편 공부중…
  3. 3. import
  4. 4. url
  5. 5. get
  6. 6. post