import requests
from urllib import request
from bs4 import BeautifulSoup
import time
import pandas as pd
import re

저는 그때그때 import 하기보다 최상단에 import 하는 편을 좋아하기 때문에 일단 사용할 라이브러리들을 불러와줍니다.

requests와 BeautifulSoup4는 크롤링에 있어서 html소스를 가져오고 정제하는 역할을 합니다.

time을 import 한 이유는 크롤링을 너무 빨리 진행하면 봇으로 인식하여 ip 차단을 당하기 때문입니다.

그리고 데이터프레임으로 저장하기 위해 pandas를 이용합니다.

- dc offical app 문자열을 삭제하기 위해 re를 불러옵니다.

df = pd.DataFrame(columns = ['contents','mbti'])

데이터프레임에서 제목과 내용을 뜻하는 contents 그리고 게시판 이름이 들어갈 mbti를 지정해줍니다.

BASE_URL = "https://gall.dcinside.com/mgallery/board/lists"
ARTICLE_BASE_URL = "https://gall.dcinside.com"

# user_agent 리스트 설정
user_agent_list = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
'Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16.2',
'Opera/9.80 (Windows NT 6.1; WOW64; U; pt) Presto/2.10.229 Version/11.62',
'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.2a1pre) Gecko',
'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko/2009032803',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/75.0'
]

BASE_URL로 마이너갤러리 기본 주소와, 원주소인 ARTICLE_BASE_URL 지정합니다.

user_agent_list 에서 choice하여 사용할 리스트는 봇으로 인식하지 않는데 도움을 줄 브라우저 정보 여러가지를 입력합니다. 

 

User-Agent는 https://www.useragentstring.com/ 를 참고하시면 됩니다.

#몇 페이지부터 몇 페이지까지
for i in range(2, 4):
	# 파라미터 설정
	params = {'id': 'intp_mbti','page':i}

	#user_agent_list로부터 choice 합니다.
	user_agent = random.choice(user_agent_list)
    
	#choice된 User-Agent를 headers로 받습니다.
	headers = {'User-Agent': user_agent}

	response = requests.get(BASE_URL, params=params, headers=headers)
	soup = BeautifulSoup(response.content, 'html.parser')

	#실질적 글 목록 부분
	article_list = soup.find('tbody').find_all('tr',{'data-type':'icon_pic'})
	article_list += soup.find('tbody').find_all('tr',{'data-type':'icon_txt'})

1단계 for에서의 작업입니다.

해당하는 부분에서는 몇 페이지부터 몇 페이지 까지 크롤링 할 것인지 결정할 수 있습니다.

User-Agent는 리스트로부터 choice를 통해 추출합니다.

params에서는 탐색할 갤러리의 / 이후 주소와 page로 i를 받았습니다.

해당하는 부분에서 소스를 불러오고

실제로 유저가 작성한을 불러오기 위해서는 icon_pic 이나 icon_txt를 포함해야 합니다.

(이 부분에 대해서 제외하기 위함입니다.)

 

과거 다른분들이 작성해주셨던 코드로는 사이트도 소스를 자주 바꾸기 때문에 그때마다 개발자 도구로 확인해서 접근해 주어야 합니다. 

	# 한 페이지에 있는 모든 게시물을 긁어오는 코드 
	for tr_item in article_list:

		# 제목 추출
		title_tag = tr_item.find('a', href=True)
		title = title_tag.text

		print("제목: ", title)
        
		#user_agent_list로부터 choice 합니다.
		user_agent = random.choice(user_agent_list)
    
		#choice된 User-Agent를 headers로 받습니다.
		headers = {'User-Agent': user_agent}
        
		# 게시물에 request
		article_response = requests.get(ARTICLE_BASE_URL + title_tag['href'], headers=headers)
		time.sleep(random.random()*2+3)
		print("url: ", article_response.url)

		article_id = (title_tag['href'].split('no=')[1]).split('&')[0]
		print("게시물 ID : ", article_id)

		article_soup = BeautifulSoup(article_response.content, 'html.parser')

2단계 for 안에서의 작업입니다. - 1

  1. article 제목은 href를 가지고 있는 a 태그에 대하여 추출하고
  2. 게시글의 url은 원 주소와 href의 값을 이용합니다.
  3. 해당하는 게시글 주소에 대해 리스트로부터 choice한 User-Agent header을 포함하여 request합니다.
  4. 게시글 번호는 href의 값에서 split을 이용한 String 정제를 이용하여 추출합니다.

마지막으로, request한 게시글 본문을 포함한 소스에 대해 정제요청을 합니다.

		# 게시물 부분의 태그
		article_contents=str(article_soup.find('div', class_='write_div'))
		article_contents=BeautifulSoup(article_contents, "lxml").text
        
		# 제목과 게시글에서 url 제거 
		pattern = 'http[s]?://(?:[a-zA-Z]|[0-9]|[$\-@\.&+:/?=]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
		repl = ''        
		title = re.sub(pattern=pattern, repl=repl, string=title)
		article_contents = re.sub(pattern=pattern, repl=repl, string=article_contents)
        
		# - dc official App 제거 
		article_contents = article_contents.replace('- dc official App', repl)
		print("내용: ", article_contents)
        
		# 제목 + 게시글
		article=title+article_contents
        
		# 내용이 있으면 데이터프레임에 저장
		if article_contents is not None:
			index = len(df) + 1
			df.loc[index] = [article,'intp']
	# 데이터프레임을 csv로 저장
	df.to_csv("intp.csv", index = False, encoding="utf-8-sig")

2단계 for 안에서의 작업입니다. - 2

  1. 게시글에서 본문에 속하는 부분은 div 태그 write_div라는 클래스에 속합니다.
  2. BeautifulSoup를 이용하여 텍스트 부분만을 추출해내어 img 태그가 담긴 부분을 배제합니다.
  3. url regex pattern을 이용하여 외부 링크를 담은 쓸모없는 내용을 제거합니다.
  4. 정보가 될 수 없는 반복되는 -dc official App에 대하여 일괄 제거합니다.
  5. 본문이 존재하지 않는 글은 저장하지 않습니다.
  6. 제목과 본문은 글쓴이의 특성을 담고 있으므로 정보가 될 수 있습니다.
  7. 제목과 본문을 합하고 데이터프레임의 마지막에 계속하여 mbti타입과 제목+본문을 저장합니다.

마지막으로 수집한 데이터가 저장된 데이터프레임을 .csv로 저장하여 데이터셋으로 확보합니다.

 

이 때, 주의해야 할 점은 encoding="utf-8-sig"를 파라미터로 지정하여야 한다는 것입니다.

그렇지 않으면 메모장에서는 열리나 엑셀에서는 안열리게 됩니다.

 

또한, 게시글에 본문이 없는 경우 일단 누락하였으며, 이후 모델링 과정에서 게시글의 길이가 과도하게 짧은 경우를 배제해야 하는지 고려해야합니다.

 

작업 결과물의 모니터링 사진입니다.

모니터링시 표시되는 내용

 

※ 해당 게시글은 아래 링크의 SourceCode를 응용하였습니다. 

[Python] 디씨인사이드 글 / 게시물 / 사진 크롤링 — 치킨과 개발의 상관관계 (tistory.com)

 

 

const remove = () => {
        const user_id = Constants.installationId;
        firebase_db.ref('/like/'+user_id+'/'+content.idx).remove().then(function(){
            Alert.alert("삭제 완료");
            // navigation.navigate('LikePage')
            reload()
        })
    }

 

삭제기능

expo의 Constants를 이용하여 고유 설치 ID넘버와 컨텐츠의 ID를 받아서 해당하는 팁을 삭제해주는 코드이다.

const like = () => {
        
        // like 방 안에
        // 특정 사용자 방안에
        // 특정 찜 데이터 아이디 방안에
        // 특정 찜 데이터 몽땅 저장!
        // 찜 데이터 방 > 사용자 방 > 어떤 찜인지 아이디
        const user_id = Constants.installationId;
        firebase_db.ref('/like/'+user_id+'/'+ tip.idx).set(tip,function(error){
            console.log(error)
            Alert.alert("찜 완료!")
        });
    }

 

 

 

 

추가기능

expo의 Constants를 이용하는것과 고유넘버를 받는것 모두 동일하며 remove.then 대신에 set으로 tip을 설정하고 그 과정에서 error을 캐치해주는 모습이다.

timeout(()=>{
        firebase_db.ref('/tip').once('value').then((snapshot) => {
          console.log("파이어베이스에서 데이터 가져왔습니다!!")
          let tip = snapshot.val();
          
          setState(tip)
          setCateState(tip)
          getLocation()
          setReady(false)
        });

조회기능

사용할 원래의DB에서 데이터를 읽어서 tip에 저장해줍니다. 또 로딩후 로딩상태를 해제하여 해당하는 페이지를 띄우는 역할입니다.

JSX를 직접 다룬것은 처음이지만, HTML CSS JS 기초지식이 있기 때문에 이해하고 제안된 디자인을 구현하는 것은 어렵지 않았다.

더보기
import React from 'react';
import main from '../assets/main.png';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import data from '../data.json';
export default function MainPage() {
  console.disableYellowBox = true;
  //return 구문 밖에서는 슬래시 두개 방식으로 주석
  let tip = data.tip;
  let todayWeather = 10 + 17;
  let todayCondition = "흐림"
  return (
    /*
      return 구문 안에서는 {슬래시 + * 방식으로 주석
    */
    <ScrollView style={styles.container}>
      <Text style={styles.title}>나만의 꿀팁</Text>
      <Text style={styles.weather}>오늘의 날씨: {todayWeather + '°C ' + todayCondition} </Text>
      <Image style={styles.mainImage} source={main}/>
      <ScrollView style={styles.middleContainer} horizontal indicatorStyle={"white"}>
        <TouchableOpacity style={styles.middleButton01}><Text style={styles.middleButtonText}>생활</Text></TouchableOpacity>
        <TouchableOpacity style={styles.middleButton02}><Text style={styles.middleButtonText}>재테크</Text></TouchableOpacity>
        <TouchableOpacity style={styles.middleButton03}><Text style={styles.middleButtonText}>반려견</Text></TouchableOpacity>
        <TouchableOpacity style={styles.middleButton04}><Text style={styles.middleButtonText}>꿀팁 찜</Text></TouchableOpacity>
      </ScrollView>
      <View style={styles.cardContainer}>
         {/* 하나의 카드 영역을 나타내는 View */}
         {
          tip.map((content,i)=>{
            return (<View style={styles.card} key={i}>
              <Image style={styles.cardImage} source={{uri:content.image}}/>
              <View style={styles.cardText}>
                <Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text>
                <Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text>
                <Text style={styles.cardDate}>{content.date}</Text>
              </View>
            </View>)
          })
         }
      </View>
    </ScrollView>
  );
}
const styles = StyleSheet.create({
  container: {
    //앱의 배경 색
    backgroundColor: '#fff',
  },
  title: {
    //폰트 사이즈
    fontSize: 20,
    //폰트 두께
    fontWeight: '700',
    //위 공간으로 부터 이격
    marginTop:50,
    //왼쪽 공간으로 부터 이격
    marginLeft:20
  },
  weather:{
    alignSelf:"flex-end",
    paddingRight:20
  },
  mainImage: {
    //컨텐츠의 넓이 값
    width:'90%',
    //컨텐츠의 높이 값
    height:200,
    //컨텐츠의 모서리 구부리기
    borderRadius:10,
    marginTop:20,
    //컨텐츠 자체가 앱에서 어떤 곳에 위치시킬지 결정(정렬기능)
    //각 속성의 값들은 공식문서에 고대로~ 나와 있음
    alignSelf:"center"
  },
  middleContainer:{
    marginTop:20,
    marginLeft:10,
    height:60
  },
  middleButton01: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#fdc453",
    borderColor:"deeppink",
    borderRadius:15,
    margin:7
  },
  middleButton02: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#fe8d6f",
    borderRadius:15,
    margin:7
  },
  middleButton03: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#9adbc5",
    borderRadius:15,
    margin:7
  },
  middleButtonText: {
    color:"#fff",
    fontWeight:"700",
    //텍스트의 현재 위치에서의 정렬
    textAlign:"center"
  },
  middleButton04: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#f886a8",
    borderRadius:15,
    margin:7
  },
  cardContainer: {
    marginTop:10,
    marginLeft:10
  },
  card:{
    flex:1,
    //컨텐츠들을 가로로 나열
    //세로로 나열은 column <- 디폴트 값임
    flexDirection:"row",
    margin:10,
    borderBottomWidth:0.5,
    borderBottomColor:"#eee",
    paddingBottom:10
  },
  cardImage: {
    flex:1,
    width:100,
    height:100,
    borderRadius:10,
  },
  cardText: {
    flex:2,
    flexDirection:"column",
    marginLeft:10,
  },
  cardTitle: {
    fontSize:20,
    fontWeight:"700"
  },
  cardDesc: {
    fontSize:15
  },
  cardDate: {
    fontSize:10,
    color:"#A6A6A6",
  },
});

 

일전에 공부하였던 map을 jsx에서 사용해서 card-gui방식으로 리스팅되게 구현하여 보았다. flex디자인이 엄청 유용함을 알 수 있다.

 

AboutPage는 구글링하여 디자인 image만을 보고 완성하여보았다. 

더보기
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity} from 'react-native';
export default function AboutPage() {
  //return 구문 밖에서는 슬래시 두개 방식으로 주석
  return (
    /*
      return 구문 안에서는 {슬래시 + * 방식으로 주석
    */
    <View style={styles.container}>
      <Text style={styles.title} numberOfLines={2}>Hi! 스파르타코딩 앱개발 반에 오신것을 환영합니다.</Text>
      <View style={styles.cardContainer}>
      <Image
        style={styles.cardImage}
        source={{
        }}
      />
      <Text style={styles.cardTitle} numberOfLines={2}>많은 내용을 간결하게 담아내려 노력했습니다!</Text>
      <Text style={styles.cardText} numberOfLines={2}>꼭 완주 하셔서 꼭 여러분것으로 만들어가시길 바랍니다</Text>
      <TouchableOpacity style={styles.cardBttn}><Text style={styles.cardAccount} numberOfLines={2}>emptyinteger@instagram</Text></TouchableOpacity>
      </View>
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    //앱의 배경 색
    backgroundColor: 'blue',
    flex:1
  },
  title: {
    //폰트 사이즈
    fontSize: 30,
    color: "#fff",
    //폰트 두께
    fontWeight: '700',
    //위 공간으로 부터 이격
    marginTop:50,
    //왼쪽 공간으로 부터 이격
    marginLeft:30,
    marginRight:10,
    marginBottom:10
  },
  mainImage: {
  },
  cardContainer: {
    marginTop:30,
    marginLeft:30,
    backgroundColor:"white",
    flex:1,
    borderColor:"black",
    justifyContent:"center",
    borderWidth: 1,
    marginRight: 28,
    marginBottom: 38,
    borderRadius: 15,
    padding:30
  },
  card:{
    flex:1,
    //컨텐츠들을 가로로 나열
    //세로로 나열은 column <- 디폴트 값임
    flexDirection:"row",
    margin:10,
    borderBottomWidth:0.5,
    borderBottomColor:"#eee",
    paddingBottom:10
  },
  cardImage: {
    //컨텐츠의 넓이 값
    //컨텐츠의 높이 값
    resizeMode:"contain",
    width:150,
    height:125,
    //컨텐츠의 모서리 구부리기
    alignSelf:'center',
    //컨텐츠 자체가 앱에서 어떤 곳에 위치시킬지 결정(정렬기능)
    //각 속성의 값들은 공식문서에 고대로~ 나와 있음
    borderRadius:15,
  },
  cardText: {
    fontSize:12.5,
    marginLeft:30,
    marginRight:30,
    marginBottom:10,
    textAlign: 'center'
  },
  cardTitle: {
    //폰트 사이즈
    fontSize: 18,
    color: "#000",
    //폰트 두께
    fontWeight: '700',
    //위 공간으로 부터 이격
    marginTop:10,
    //왼쪽 공간으로 부터 이격
    marginLeft:30,
    marginRight:30,
    marginBottom:10,
    textAlign: 'center'
  },
  cardAccount: {
    backgroundColor:"orange",
    borderRadius: 30,
    padding:20,
    width:'70%',
    fontSize:15,
    alignSelf: 'center',
    textAlign: 'center',
  },
  cardBttn: {
    backgroundColor:"orange",
    borderRadius: 15,
    width:200,
    alignSelf:'center'
  },
});
 
]
 
 
 

 

 
 

아직은 정말 간단하게 GUI만을 구현하여 보았는데, 앞으로 API들을 이용할것이 기대된다.

 

 

 

Python의 beautifulsoup과 request를 import 하여서 네이버 영화와 지니 음악 스트리밍 사이트의 영화와 음악 목록들을 크롤링해보았다. 

headers를 사용한 이유는 일반적인 request가 대부분의 사이트에서 보안이슈 등으로 잠겨있기 때문에 내가 요청하는 py코드가 브라우저라고 착각하게 만드는 코드이다.

 

import requests
from bs4 import BeautifulSoup
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get('https://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=pnt&date=20200303',headers=headers)

soup = BeautifulSoup(data.text, 'html.parser')

trs = soup.select('#old_content > table > tbody > tr')
# 코딩 시작
print(trs)

for tr in trs:
    a_tag = tr.select_one('td.title > div > a')
    if a_tag is not None:
        rank = tr.select_one('td.ac > img')
        rank = rank['alt']
        title = a_tag.text
        star = tr.select_one('td.point')
        star = star.text
        print(rank , title, star)
        doc = {
            'rank':rank,
            'title':title,
            'star':star
        }

 

또한 MongoDB를 이용하여 크롤링한 데이터를 저장해보기도 하였다. 기존에 MariaDB를 SQL로 다뤄봤는데 CLI로 다루었으나, 이번에는 NoSQL타입인 MongoDB에 Pymongo를 이용하여 데이터를 조작하고 조작한 데이터를 Studio3T라는 GUI 어플리케이션으로 다루어보았다.

# 저장 - 예시
doc = {'name':'bobby','age':21}
db.users.insert_one(doc)

# 한 개 찾기 - 예시
user = db.users.find_one({'name':'bobby'})

# 여러개 찾기 - 예시 ( _id 값은 제외하고 출력)
same_ages = list(db.users.find({'age':21},{'_id':False}))

# 바꾸기 - 예시
db.users.update_one({'name':'bobby'},{'$set':{'age':19}})

# 지우기 - 예시
db.users.delete_one({'name':'bobby'})

 

아래는 지니뮤직을 크롤링해보았다.

import requests
from bs4 import BeautifulSoup
import requests

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get('https://www.genie.co.kr/chart/top200?ditc=D&ymd=20200403&hh=23&rtm=N&pg=1',headers=headers)

soup = BeautifulSoup(data.text, 'html.parser')

trs = soup.select('#body-content > div.newest-list > div > table > tbody > tr.list')
# 코딩 시작
for tr in trs:
    title = tr.select_one('td.info >  a.title')
    artist = tr.select_one('td.info > a.artist')
    rank = tr.select_one('td.number')
    if title is not None:
        title = title.text.strip()
        artist = artist.text.strip()
        rank = rank.text[0:2].strip()
        print(rank,title,artist)

지니뮤직에서는 음악의 제목과 가수 그리고 순위를 크롤링하여서 trim()과 비슷한 strip()을 이용하여 공백을 제거하여보았다. rank가 아니라 str처리된 text의 뒤에 [0:2]를 하여야 필요한 부분만 추출 할 수 있음을 알게 되었다.

오늘은 Ajax를 활용하여 openAPI를 사용하는 방법을 다뤄보았다.

onclick,그리고 $(document).ready로 호출하는 두가지 방법으로 활용해 보았고 코드는 다음과 같다.

$.ajax({
        type: "GET",
        url: "http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99",
        data: {},
        success: function(response){
            $('#names-q1').empty()
            let mise = response['RealtimeCityAir']['row']
            mise.map((value,index) => {
                let gu = value['MSRSTE_NM']
                let pm = value['IDEX_MVL']
                if (pm>70){
                    $('#names-q1').append(`<li class="bad">${gu} : ${pm}</li>`)
                }else{
                    $('#names-q1').append(`<li >${gu} : ${pm}</li>`)
                }
            })
            console.log(response)
        }
    })
}

 

위 코드는 서울시 구별 미세먼지 딕셔너리 리스트를 불러와서 필요한 값을 추출 후 나타내는 것이다.

function q1() {
  //Ajax
    $.ajax({
        type: "GET",
        url: "https://api.thecatapi.com/v1/images/search",
        data: {},
        success: function(response){
            $('#img-cat').attr("src",response[0]['url'])
            console.log(response[0]['url'])
        }
    })
}

 

위 코드는 onclick 시 랜덤 고양이 사진을 불러오는데 활용하였다.

$('id-name').attr("속성",값)을 하면 쉽게 값을 바꿀 수 있다는것을 알았다.

function q1() {
    //Ajax
    $.ajax({
        type: "GET",
        url: "http://spartacodingclub.shop/sparta_api/seoulbike",
        data: {},
        success: function(response){
            $('#names-q1').empty()
            let bike = response['getStationList']['row']
            bike.map((value,index) => {
                let gu = value['stationName']
                let slot = value['rackTotCnt']
                let parking = value['parkingBikeTotCnt']
                if (parking<10){
                    $('#names-q1').append(`<tr>`)
                    $('#names-q1').append(`<td class="redm">${gu}</td>`)
                    $('#names-q1').append(`<td class="redm">${slot}</td>`)
                    $('#names-q1').append(`<td class="redm">${parking}</td>`)
                    $('#names-q1').append(`</tr>`)
                }else{
                    $('#names-q1').append(`<tr>`)
                    $('#names-q1').append(`<td>${gu}</td>`)
                    $('#names-q1').append(`<td>${slot}</td>`)
                    $('#names-q1').append(`<td>${parking}</td>`)
                    $('#names-q1').append(`</tr>`)
                }
            })
            console.log(response)
        }
    })
}

 

위 코드는 HTML의 <table>,<thread>태그에 <tbody>부분에 들어가는 요소들을 갱신시켜주는데 표 형식으로 나타내고 갱신하는 방법을 연습하였다.

자바스크립트에서 map함수라는것을 사용해보았다.

list.map((value,index) => {

    contents

})

위와같이 표현이 가능한데 이것은 for함수에서처럼 선언하여 뽑아오고 함수의 길이를 알아보지 않아도 리스트의 값과 인덱스를 뽑아올 수 있는 유용한 함수이다.

다음과 같이 활용해 보았다.

더보기
let fruit_list = ['사과','감','감','배','포도','포도','딸기','포도','감','수박','딸기']
let count = 0
fruit_list.map((fruit,index) => {
    if(fruit=='딸기'){
        count++
    }
})
console.log(count)
더보기
let checkEmail = (email) => {
    var regExp = /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i;
    if(0<email.indexOf('@')){
        return regExp.test(email);
    }
}
let tOrF = (bool) => {
    if(bool){
        console.log('이메일이 맞습니다.')
    }else{
        console.log('이메일이 아닙니다.')
    }
}
tOrF(checkEmail('emptyinteger@gmail.com'))// 이메일이 맞습니다
tOrF(checkEmail('emptyinteger$gmail.com'))// 이메일이 아닙니다.

'프론트엔드 > JavaScript' 카테고리의 다른 글

JSX 입문 Card-GUI 중심으로 앱 페이지 제작  (0) 2022.04.07
Ajax 활용하기  (0) 2022.03.30

+ Recent posts