1. 포인터

Low level programming language :  C언어와 같이 컴퓨터가 쉽게 이해하도록 프로그래밍하는 것. 실행 속도가 빠르지만 배우기 어렵다 유지보수가 힘들다 이런 언어들은 메모리 파트에 접근할 수 있다 그것이 바로 포인터!

 

예시1)

a=2

b=a        일 때 b는 a의 값을 복사해서 가져온다

a=10       후에 b와는 상관없이 a값에 10을 가져오면 a는 10이 된다

a와 b의 값은 각각 10,2

 

& : &뒤에 나오는 값이 가지는 메모리 주소를 알려주는 기능이다

예시2)

a=2

b=&a      b는 a의 주소 값을 가져온다

a=10       

a와 b의 값은 각각 10, a의 주소 값

 

* : *뒤에 나오는 주소가 가지는 값을 알려주는 기능이다 (씨쓰루)

예시 3)

a=2

b=&a

*b의 값은 2

*b=5일 때

a의 값은 얼마일까?

*b로도 a값을 바꿀 수 있기 때문에 답은 5이다

 

이렇게 포인터를 알아보았는데 포인터는 컴퓨터에서 복사가 아닌 바로가기의 느낌이다

 

복사는 용량 전체를 가져오지만 바로가기는 연결만 할 뿐 내용 전체를 담아오지는 않는다

 

두 개의 변수가 하나의 object로 서로 연결되어있기 때문에 빠르게 대응할 수 있다

b = a, a = 2 b = &a, a = 2
&a = a주소값

&b = b주소 값

&a = a주소값 &b = b주소값
a = a b = a a = a b = &a
*(&a) = 2 *(&b) = 2 *(&a) = 2 *(&b)! = 2
    *a = error *b = 2

b=&a인 경우에도 &b=b의 주소 값을 가진다 하지만 *(&b)는 2가 아니고 &a이다

2. Arrays and Slices

Array : Go에서 Array(배열)은 요소의 개수와 형태를 입력해주어야한다

 

ex)

  names := [5] string{"nico","lynn","dal","pavk"} //요소개수를 정했다면 그보다 많이 적을 수는 없다

  names[4]="hui"  //요소를 추가하는 방법

  names[5]="asd" //6번째 이름을 추가하는 것이므로 에러가 난다 

 

Slices : 하지만!! Slices는 제한이 없는 배열이다 융통성있는 배열

 

ex)

  names := [ ] string{"nico","lynn","dal","pavk"} //요소개수를 비움으로서 요소개수제한이 없다

  names = append(names, "hui") //slice에 요소를 추가하는 방법

※append는 slice를 수정해서 요소를 추가하는 것이 아닌 요소가 추가된 새로운 slice를 반환한다

  

3. Map

map : 파이썬의 dictionary와 비슷한 형태이다 key와 value형태를 가지고 있다

 

ex)

  pavk :=map[string]string{"name":"pavk","age":"25"}

//key와 value 형태를 string으로 지정했으면 숫자여도 "25"이렇게 써줘야한다

 

ex)map을 활용한 반복문

  pavk :=map[string]string{"name":"pavk","age":"25"}

  for key,value := range pavk{ //배웠던 반복문 처럼 쓰면 되는데 배열과 다르게 index를 반환하지않고 key를 반환한다

       반복할 내용

  }  

 

 

1. for 반복(loop) 문

go에서는 for문만을 사용한다

 

forEach나 for in 같은 경우는 사용할 필요가 없다고 한다

 

왜냐하면 range를 사용할 것이기 때문이다 

(1) range

range란? 각각의 배열 요소에 반복할 내용을 실행시킨다

 

형태 : for 변수 := range 범위가 될 어떤 것(배열, 슬라이스, 문자열){

                  반복할 내용

         }

 

예시) superAdd함수에 들어있는 인자(2,3,4,5,7,9)의 개수 6개만큼 numbers를 출력한다  ≒forEach( ) in javascript

func superAdd(numbers ...int) int{
	for number := range numbers{ //반복할 횟수는 numbers의 개수
		fmt.Println(number)	 //반복될 내용
    }
	return 1
}

func main(){
	superAdd(2,3,4,5,7,9)       //numbers의 개수는 6개
}

실행결과를 보면 

이렇게 나오게 되는데 배열 요소의 개수만큼 자동으로 index값을 받게 되어서라고 한다

array(배열)과 slice(슬라이스: 융통성 있는 배열?)에서 range반복문은 index값과 배열 안의 값을 생성한다(index먼저 생성)

 

index를 보기 싫다면 for의 변수 중 처음은 무시하고( _ 언더바 사용 ) 두 번째 것을 입력하면 된다

이렇게

func superAdd(numbers ...int) int{
	for _,number := range numbers{ 
		fmt.Println(number)	 
    }
	return 1
}

func main(){
	superAdd(2,3,4,5,7,9)       

(2) i 사용

C언어와 비슷하다

꼭 i만 써야 되는 것은 아니다(하지만 아마도 수는 안될 것이다)

형태: for i:=0; i <범위(대신 수 형태여야 함); i++{

            반복할 내용

       }

(3) 총합 구하기 예제

package main

import (
	"fmt"
)

func superAdd(numbers ...int) int {
	total := 0                   	//총합이 되어줄 친구 반복문 밖에 있어야함
	for _, number := range numbers {//index는 보기싫어서 _로 무시
		total = number + total		//total변수에 각각의 수를 더해주기
	}
	return total
}

func main() {
	result := superAdd(2, 3, 6, 7, 9, 10)
	fmt.Println(result)
}

//결과 37

요약

1. for만 사용(for in, forEach 없음)

2.range는 배열에선 index값을 먼저 생성한다

3.i 같은 변수로도 범위를 구할 수 있다

 

2. if ~ else, switch~case

1. if ~ else

1) 다른 언어들과 다르게 ( )이나 :이 필요 없다

2) VScode에서 제공하는 extention return값을 주면 else를 쓸 필요 없다

3) if문을 쓰는 도중에 변수를 생성할 수 있다(무엇을 위한 변수인지 알아보기 쉬움) 

	if koreanAge := age + 2; koreanAge < 18 { //(),:필요없이 조건 바로적음 //koreanAge := age + 2; if문을 쓰는 도중에 변수만들기
		return false
	} 
	return true //else{ return true} 였을텐데 return true만 적어도 실행가능 
	

else if 조건을 추가할 때 쓰임

if 조건{

 

} else if 조건{

 

} else {

 

}

2. switch/case

1) C나 javascript와 많이 비슷하다(파이썬은 switch를 사용하지 않음)

2) if~else와 마찬가지로 쓰는 도중에 변수를 생성할 수 있다

3) else if를 도배할 필요 없이 case로 짧게 짧게 쓸 수 있다

 

package main

import (
	"fmt"
)

func canIdrink(age int) bool {
	switch koreanAge= age+2; koreanAge { //switch문 도중 변수 선언 가능
	case age < 18:			//만약 if문을 썼다면 else if로 도배될 것을 case로 짧게 짧게
		return false
	case age ==18:
		return true
	}
	return false
}

func main() {
	result := canIdrink(18)
	fmt.Println(result)
}

 

1. main Package

패키지란?

Go언어가 코드의 모듈화, 코드의 재사용과 같은 기능을 제공하기위해 사용하는 것이다

 

이전에 만든main.go는 패키지라고 불리고 앞서 말했듯 컴파일러에게 특별하게 인식된다

 

컴파일러는 main.exe(실행파일)을 만든다

 

Go에서는 main package를 쓰고 있다는 것을 작성해주어야한다

또 main package는 main 함수를 필요로한다 Go 프로그램의 시작점이 되는 부분이기 때문이다(C의 느낌이 강하게 난다)

package main

func main() {
} 

프로그램을 실행시키는 방법도 특이하다 터미널(명령 프롬프트)에 파일 저장 후 go run main.go라 입력해야 한다

 

2. fmt Package and Import

fmt는 formatting을 위한 패키지이다 이때 중요한 것은 함수 첫 글자는 항상 대문자로 써야한다는 점이다

그렇지 않을경우 나타나지지 않는다

 

첫글자가 소문자일경우는 private한 함수이고 대문자일 경우는 export된 함수이기 때문이다(이건 Go에서 지정한 약속같다)

package main

import "fmt"

func main() {
fmt.Println("Hello world!") //Println의 P가 대문자이다 export!
}

※컨트롤키를 누른채 fmt를 클릭하게된다면 fmt 안의 내용을 알 수 있다  또 fmt를 사용하지 않게 되면 자동으로 import문이 사라진다 (VScode의 장점)

3. function(함수)

변수와 상수 variable(=var), constant(=const) 각각 '변할수 있음'과 '변할수 없음'

 

Go에서 변수를 선언하기위해서는 type도 알려주어야한다 ex) var name string = "pavk"

 

함수 안에서는 이것을 축약형으로 name :="pavk"라고 쓸 수 있다(type은 Go가 알아서 찾아준다고 한다ㅎㅎ)  

name := "nico" //축약형
var name string = "lynn" //원래(너무 김)

 

또한 Go는 만들어 놓고 쓰지 않는 것을 굉장히 싫어한다 쓰지않으면 에러를 발생시킨다

 

 

Go는 함수에서 반환값을 2개 이상 가질 수 있다 (<--이것이 아마 병행성의 이유이지 않을까?)

또한 println처럼 인자를 무제한으로 가지려면 ...type을 써주면  된다

func lenAndUpper(name string) (int, string) {
	return len(name), strings.ToUpper(name) //2개의 반환값을 반환함!!
}

func repeatMe(words ...string) { //'...'만 있다면 무제한 인자!!
	fmt.Println(words)
}

func main() {
	repeatMe("nico","lynn","dal","marl","flynn","pavk")//이렇게 많은 인자도 출력이 가능하다
}

naked return : 반환값을 return 뒤가 아니라 반환값의 type 앞에 적을 수 있다

defer : 반환을 한 후에 추가로 실행을 시킬 수 있다  

func lenAndUpper(name string) (lenght int, uppercase string) { //여기 type들 앞에서 변수처럼 만들어지고 반환값으로도 사용된다
	defer fmt.Println("I'm done") //반환하고 추가로 I'm done을 출력함
	lenght = len(name)
	uppercase = strings.ToUpper(name)
	return			//여기가 아니라
}

defer를 화인해보기위해서 출력을 해보았다

package main

import (
	"fmt"
	"strings"
)

func lenAndUpper(name string) (length int, uppercase string) {
	defer fmt.Println("I'm done")//2.두번째로 실행되어야한다
	length = len(name)
	uppercase = strings.ToUpper(name)
	fmt.Println(length, uppercase)  //1.먼저 실행되어야 defer가 실행되는것을 알 수 있다
	return
}

func main() {
	totalLength, up := lenAndUpper("nico")
	fmt.Println(totalLength, up)//3.세번째
}

 

실행결과!

 

예전부터 Go언어를 접해보고 싶었지만 영어 때문에 안 배우고 있었는데

 

슬랙에 올라온 한국어 패치가 되었다는 내용을 보자마자 달려갔다(올라온지는 꽤 됐었고 어제 봤음)

https://nomadcoders.now.sh <--노마드코더 슬랙

 

그래서 Go란 무엇이냐?

Go는 2009년 구글이 개발한 프로그래밍 언어로 가비지 컬렉션 기능이 있고, 병행성을 잘 지원하는 컴파일 언어라고 한다

 

(1) 가비지 컬렉션(쓰레기 수집?)? ==> 메모리 관리 기법 중의 하나로, 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요 없게 된 영역을 해제하는 기능이다.

 

(2) 병행성? ==> 컴퓨터 과학에서 여러 계산을 동시에 수행하는 시스템의 특성으로, 잠재적으로는 서로 상호 작용이 가능하다. 이와 상대적인 개념으로는 병렬성이 있다

 

(1)(2)를 합치면? 실행 속도가 빠르다!! 

 

니꼬쌤도 빠르다는 것을 빨리 보여주고 싶어서 앞서 우리가 했던 파이썬 스크래핑과 Go스크래핑을 비교하며 보여줬다

 

온라인 세팅은 파이썬 때와 마찬가지로 Repl.it을 사용할 수 있다

 

하지만 나는 니꼬쌤이 추천한 VScode(Visual Studio Code)와 Go를 설치하고 실행했다(오프라인)

VScode는 에디터 Go는 프로그래밍 언어이다

https://code.visualstudio.com/Download <--VScode는 여기서 윈도우, 맥, 리눅스 등 다양한 버전에 맞게 설치를 한다

https://golang.org/dl/<--Go는 여기서  윈도우, 맥, 리눅스 등 다양한 버전에 맞게 설치를 한다

 

Go를 설치할 때 주의할 점은 로컬 드라이브에 go폴더와 bin폴더를 만들어 주어야 한다 ex) C:\go\bin

 

go폴더는 GOPATH환경을 위해 꼭 필요하다고 한다 (자세한 내용은 Go를 다운로드하는 버튼을 클릭하면 나옴 영어로)

 

main.go는 go폴더 안의 src폴더 안의 github.com안의 자신의 닉네임 폴더 안의 learngo폴더에 저장해주면 좋다

ex) C:\go\src\github.com\pavk\learngo\main.go(없으면 생성해야 함)

 

main.go는 컴파일하기 위해서 꼭 필요한 패키지이다

 

공유, 오픈소스코드를 만들기 위함이라면 main.go를 만들면 안된다

 

나는 window10 사용자여서  VScode를 실행하여 새 파일을 생성고 저장을 통해 이름과 확장자를 main.go로 바꾸었다

 

그러면 VScode에서 Go를 사용하기 위해 업데이트를 하라고 막막막 뜨는데 그것을 다 하자는 대로 해주면 된다

 

이런 화면이 나왔다면 성공! 기본적인 세팅은 끝났다

 

네이버뉴스 스크래핑!

저번시간에 배운 것들을 토대로 네이버의 종류별 뉴스부분을 스크래핑한다 

원래는 번개장터나 중고 물품거래사이트에서 lg그램을 검색하면 나오는 페이지들을 스크래핑하려했다

 

하지만 이렇게 거래 또는 보안을 엄격하게 걸어놓은 사이트들은 스크래핑이 되지 않는것같았다

 

배운대로 6단계에 걸쳐서 시행해 보았다

1. 먼저 requests와 BeautifulSoup의 패키지를 다운받고 네이버 URL을 가져왔다

import requests
from bs4 import BeautifulSoup

URL = 'https://www.naver.com/'

2. 마지막 페이지로 쓰일 것은 이번엔 페이지 번호가 아닌 분류명(리빙,푸드,스포츠,자동차 등등 28개의 종류들)

div태그 중 class명이 "rolling-container"인 것을 찾고 그중 li태그로 이루어진 모든것을 리스트화 시켰다

반복문을 통해 분류명이 텍스트형식으로 리스트에 들어가도록 했다 (그 이유는 get_text함수는 리스트 자체를 못 쓴다)

새로운 리스트에 텍스트를 담아주면 마지막 페이지 수는 리스트의 길이로 체크했다

def get_last_pages():
  result = requests.get(URL)
  s = BeautifulSoup(result.text, "html.parser")
  links = s.find("div",{"class":"rolling-container"}).find_all("li")
  page=[] 	#새로운 리스트
  for i in range(len(links)): #리스트 자체를 get_text하지못하기때문에 반복문을 사용
    page.append(links[i].get_text(strip="\n"))
  max_page = len(page)
  return max_page

 

3. 요소로는 제목과 링크를 가져오기로 했다

def extract_job(html):
  result = requests.get(URL)
  s = BeautifulSoup(result.text, "html.parser")
  title_r = s.find("span",{"class": "td_t"})
  title=title_r.get_text()
  link= s.find("li",{"class":"tl_default"}).find("a")["href"]
  return {
        "title": title,
        "link": link
  }

4. 모든 페이지를 찾고 요소들을 리스화 했다

def extract_jobs(last_page):
  jobs = []
  for page in range(last_page): 
    print(f"Scrapping Indeed: Page: {page}")
    result = requests.get(URL)
    s = BeautifulSoup(result.text, "html.parser")
    results = s.find_all("li", {"class": "tl_default"}) #사실 이 부분만 빼면 나머지는 거의 같다
        job = extract_job(result)
        jobs.append(job)
  return jobs

그리고 깔끔한 마무리~

def get_jobs():
  last_page=get_last_pages()
  jobs=extract_jobs(last_page)
  return jobs

5. CSV파일로 만들기와 6.스프레드시트에 불러오기는 https://jejehoon.tistory.com/15를 참고하면 된다

 

 

완성!!!!!!!!!

 

이것도 따라한거라고 생각하지만 막상 해보니 막히는 부분이 생기면서 시간이 엄청 지체되었다

React JS로 날씨앱 만들기는 따라만하고 직접 다시 만들어보지는 않았었다 

복습을 통해서 다시 떠올리고 또 새로운걸 알아가는 계기가 되었다 좋았다

 

 

다음은 Go언어! 

 

4. 요소들 리스트 화하기

이 단계에서는 전체 데이터를 jobs라는 리스트에 담는 것을 진행했었다

 

원래 title요소를 찾을 때 했었지만 20페이지 모두 매번 볼 수 없었기 때문에 니꼬쌤은 다른 함수로 옮겼다

 

def extract_jobs(last_page):  		#모든데이터 추출하는 함수
  jobs = []							#빈 리스트 jobs만들기
  for page in range(last_page): 	#마지막페이지까지 아래를 실행하는 반복문
    print(f"Scrapping Indeed: Page: {page}")	#되는지 안되는지 보기위한 출력문장
    result = requests.get(f"{URL}&start={page*Limit}")	
    s = BeautifulSoup(result.text, "html.parser")
    results = s.find_all("div", {"class": "jobsearch-SerpJobCard"})#모든 페이지 jobcard가져오기
    for result in results:
        job = extract_job(result)#제목,회사명,위치,링크추출하는 함수 실행
        jobs.append(job) #리스트에 넣기
  return jobs	#반환값

마지막으로 get_jobs함수를 만들어 나머지 세 개의 함수를 잘 정리했다

def get_jobs():
  last_page=get_last_pages()
  jobs=extract_jobs(last_page)
  return jobs

인디드는 끝!!

 

스택오버플로우는 이와 같이 반복 진행하므로 생략한다(물론 약간씩 다른 부분도 있어서 영상을 보는 것이 훌륭하다)

 

https://academy.nomadcoders.co/courses/

 

Academy

[풀스택] 인스타그램 클론 코딩 2.0 인스타그램 백엔드 + 프런트엔드 + 앱 + 서버 [중급] NodeJS, Prisma, GraphQL, Hooks, React Native % Complete

academy.nomadcoders.co

노마드 코더스 아카데미에서 파이썬으로 웹 스크래핑 영상이 있다

무료이다 (20년 3월 기준)

 

5.CSV로 파일 저장

CSV란? 콤마(Comma)로 데이터들을 구분한 파일이라는 뜻 엑셀이나 스프레드시트에 사용할 수 있다

 

인디드나 스택오버플로우와 마찬가지로 save.py를 만들어 코드를 작성한다

(main.py에는 오직 각 모듈에서 나오는 함수들만 있도록 깔끔하게)

 

먼저 save.py에서 파이썬에 내장된 CSV모듈을 import 해준다

(CSV모듈을 import 해주면 csv파일을 작성할 수 있다)

 

또한 각 파일로부터 반환된 jobs를 파이썬에 내장된 함수 open을 통해 생성해준다

 

이때 확장자는 csv , 모드는 w로 해준다

모드란? 파일을 열 때 어떤 형식으로 열지 정하는 것이다 w=write(쓰기), r=read(읽기), a=append(마지막에 추가하기)

 

CSV모듈 중 writer함수를 통해 제목, 회사명, 위치, 링크 순으로 각 위치에 리스트 형식으로 내용을 담아준다

 

우리가 반환한 인디드 값은 딕셔너리 형태이다

 

그렇게 된다면 스프레드시트에서 title: blablalba 이런 형태로 모든 것이 나오게 된다

 

이것을 없애기 위해 value함수를 통해 blablalba만 가져오자 

 

작성한 코드

 

import csv

def save_to_file(jobs):
  file = open("jobs.csv", mode="w")
  writer = csv.writer(file)
  writer.writerow(["title","company","location","link"])
  for job in jobs:
    writer.writerow(list(job.values()))
  return 

main.py에는 이런 식으로 인디드와 스택오버플로를 합쳐 저장했다

from indeed import get_last_pages
from so import get_jobs as get_so_jobs
from save import save_to_file

indeed_jobs = get_indeed_jobs()
so_jobs = get_so_jobs()
jobs = so_jobs + indeed_jobs

save_to_file(jobs)

 

이후 실행시켜보면

이런 형태로 jobs.csv에 저장이 된다 

6.스프레드시트에 불러오기

Repl.it에서 모든 파일을 압축 형식으로 다운로드하여 자신이 알 수 있는 공간에 풀어준다

풀었다면 구글의 온라인 스프레드시트에 들어가 job.csv를 import 해준다

밑의 그림처럼 나온다면 성공이다

감사합니다 니꼬쌤 김취 포테이토 냠냠

 3. 요소들 찾기

이전에 작성한 코드 

import requests
from bs4 import BeautifulSoup

 
result = requests.get(URL)
s = BeautifulSoup(result.text, "html.parser")

pagination = s.find("div", {"class": "pagination"})
links = pagination.find_all('a')

pages = []
for link in links[:-1]:
	pages.append(int(link.string))
    
max_page = pages[-1]

니꼬쌤은 import를 제외한 코드들을 함수로 쪼개는 편이 좋다고 한다 

그 이유는 깔끔하니까

main.py는 가장 먼저 실행되는 메인 파일이다 

니꼬쌤은 indeed.py를 만들어 코드를 작성했다 

커다란 장농에 칸마다 종류별 옷들을 정리하는 것 같았다

 

그래서 이것을 get_last_pages라는 함수를 만들어 그 안에 넣었다

def get_last_pages():
    result = requests.get(URL)
    s = BeautifulSoup(result.text, "html.parser")
    
    pagination = s.find("div", {"class": "pagination"})
    links = pagination.find_all('a')
  
    pages = []
    for link in links[:-1]:
        pages.append(int(link.string))
    
    max_page = pages[-1]
    return max_page

대부분의 함수는 전에 말했듯 반환해야 하는 값이 필요하다 

 

우리가 찾고자하는 값은 마지막 페이지이므로 max_page를 반환 값으로 지정했다

 

이와 마찬가지로 제목과 회사, 위치, 링크의 각각의 태그들을 찾아준다

def extract_job(html):
    title = html.find("div", {"class": "title"}).find("a")["title"]
    company = html.find("span", {"class": "company"})
    company_anchor = company.find("a")
    if company_anchor is not None:
        company = str(company_anchor.string)
    else:
        company = str(company.string)
    company = company.strip()
    location = html.find("div", {"class": "recJobLoc"})["data-rc-loc"]
    job_id = html["data-jk"]
    return {
        "title": title,
        "company": company,
        "location": location,
        "link": f"https://kr.indeed.com/%EC%B1%84%EC%9A%A9%EB%B3%B4%EA%B8%B0?&jk={job_id}"
    }

 

extract_job함수로 모은 요소들

 

title = html.find("div", {"class": "title"}).find("a")["title"]

제목을 찾을 때 a태그의 문자열을 가져왔더니 문자열로 저장되지 않은 부분이 있었다 

 

그래서 a태그 안에 있는 속성값 "title"로 구분을 해주었다 

속성 값을 찾을 때는 [ ]로 표시한다

 

company = html.find("span", {"class": "company"})
    company_anchor = company.find("a")
    if company_anchor is not None:
        company = str(company_anchor.string)
    else:
        company = str(company.string)
    company = company.strip()
    location = html.find("div", {"class": "recJobLoc"})["data-rc-loc"]

회사명을 찾을 때는 a태그의 문자열을 가져왔더니 링크가 저장되지 않은 부분이 있었다

print 해보면 None이 나왔다

 

또 여기는 a태그 안에 있는 속성 값에도 회사명이 없었다

 

그래서 if else 조건문으로 저장된 부분은 a태그의 문자열을 

저장되지 않은 부분은 span태그의 문자열을 가져오도록 했다

location = html.find("div", {"class": "recJobLoc"})["data-rc-loc"]

위치를 찾을 때도 제목처럼 속성값을 사용해 문자열을 찾았다

job_id = html["data-jk"]

링크는 클릭해서 들어가보면 페이지 URL맨 끝에 jk=어쩌고 저쩌고로 끝이 난다

 

어쩌고 저쩌고가 링크들을 구분할 수 있는 것이고 그것은 data-jk라는 속성에 있었다

 

return {
        "title": title,
        "company": company,
        "location": location,
        "link": f"https://kr.indeed.com/%EC%B1%84%EC%9A%A9%EB%B3%B4%EA%B8%B0?&jk={job_id}"
    }

 마지막으로 리스트 형식으로 반환해주고 extract_job함수에 넣어주었다

 

내 턴을 종료했다

 

작성한 코드

import requests
from bs4 import BeautifulSoup

Limit = 50
URL = f'https://kr.indeed.com/%EC%B7%A8%EC%97%85?as_and=Python&as_phr=&as_any=&as_not=&as_ttl=&as_cmp=&jt=all&st=&as_src=&radius=25&fromage=any&limit={Limit}&sort=&psf=advsrch&from=advancedsearch'

def get_last_pages():
    result = requests.get(URL)
    s = BeautifulSoup(result.text, "html.parser")
    pagination = s.find("div", {"class": "pagination"})
    links = pagination.find_all('a')
    print(links)
    pages = []
    for link in links[:-1]:
        pages.append(int(link.string))
    print(pages)
    max_page = pages[-1]
    return max_page

def extract_job(html):
    title = html.find("div", {"class": "title"}).find("a")["title"]
    company = html.find("span", {"class": "company"})
    company_anchor = company.find("a")
    if company_anchor is not None:
        company = str(company_anchor.string)
    else:
        company = str(company.string)
    company = company.strip()
    location = html.find("div", {"class": "recJobLoc"})["data-rc-loc"]
    job_id = html["data-jk"]
    return {
        "title": title,
        "company": company,
        "location": location,
        "link": f"https://kr.indeed.com/%EC%B1%84%EC%9A%A9%EB%B3%B4%EA%B8%B0?&jk={job_id}"
    }

 Limit= 50 은 URL의 jobcard개수를 50개로 제한한다는 의미이다 

25로 고치면 25개를 볼 수 있다

 

2. 페이지 인덱스를 수로 만들기

이전에 작성한 코드

import requests
from bs4 import BeautifulSoup


result = requests.get(URL)
soup = BeautifulSoup(result.text, "html.parser")

URL을 beautifulsoup를 통해 html형태로 파싱을 했다

그렇다면 특정 태그와 클래스명 등을 통해 데이터를 추출할수 있다

 

※html은 페이지의 코드라고 설명할 수 있는데 

<html></html>이런식의 태그형태로 대부분 이루어져있다 

 

요소들마다 가진 고유한 태그 또는 속성들을 찾아야만 데이터를 추출할 수 있다

 

우리가 찾고자하는 것은 페이지 인덱스!

 

페이지의 인덱스는 이렇게 생겼다

html태그들 중에 페이지 인덱스를 표현하는 태그를 찾으려면 

 

페이지에서 우클릭 후 검사를 클릭하면 html태그들이 쫙 나온다

 

거기에 마우스를 갖다대면 그태그가 가리키는 요소들을 이런식으로 표현해준다 

find함수를 통해 이 중 인덱스를 포함하는 태그를 찾아 준다

 

※find함수는 선택한 태그 하나를 찾아준다

find_all함수는 선택한 태그의 모든것(속성,클래스,아이디 등등)을 찾아주며 그것을 리스트의 형태로 나타낸다

pagination = soup.find("div", {"class": "pagination"})
indexs = pagination.find_all('a')

pages라는 변수에 빈리스트를 만들어 준다

 

indexs를 문자열 형태만 추출해 정수형으로 바꿔준 뒤 리스트에 넣어준다

왜냐하면 indexs안에는 태그의 모든 것이 들어있고 우리가 찾고자하는 것은 수이기 때문이다

pages = []
for index in indexs[:-1]:
    pages.append(int(link.string))

[:-1]는 리스트에 있는 문자열 중 처음부터 제일 마지막까지라는 의미이다

나는 10까지의 페이지 인덱스가 있었으므로 마지막 페이지는 10이다

max_page = pages[-1] #max_page = 10

 

작성한 코드

import requests
from bs4 import BeautifulSoup

 
result = requests.get(URL)
s = BeautifulSoup(result.text, "html.parser")

pagination = s.find("div", {"class": "pagination"})
links = pagination.find_all('a')

pages = []
for link in links[:-1]:
	pages.append(int(link.string))
    
max_page = pages[-1]

+ Recent posts