반응형

출처: http://funnyksoo.blogspot.kr/2015/08/python-reading-excel-sheet-with-xlrd.html


1. xlrd

시작에 앞서 python xlrd패키지를 설치해야 합니다.
https://pypi.python.org/pypi/xlrd/0.7.9

xlrd와 xlwd 두개의 패키지가 존재하는데, xlrd는 read용 패키지 xlwd는 write용 패키지 입니다.

먼저 포스팅에 사용할 엑셀 Sheet은 아래와 같이 작성됐습니다.

Sheet1


Sheet2










2. Open the Excel files and sheets


__author__ = 'Administrator'
import xlrd
wb = xlrd.open_workbook("C:\\test.xlsx")
ws = wb.sheet_by_index(0)
ncol = ws.ncols
nlow = ws.nrows
print "-------- Sheet1 --------"
print "Number of col: " + str(ncol)
print "Number of low: " + str(nlow)
ws = wb.sheet_by_index(1)
ncol = ws.ncols
nlow = ws.nrows
print "-------- Sheet2 --------"
print "Number of col: " + str(ncol)
print "Number of low: " + str(nlow)
view rawgistfile1.txt hosted with ❤ by GitHub

위와 같이 xlrd를 import 해줍니다.

Lien 4 - xlrd.open_workbook()을 통해 Excel파일을 읽어옵니다.

Line 5, 13  - sheet_by_index()를 통해 line 5에선 Sheet1 line 13에선 Sheet2를 각각 열람 할 수 있습니다.

Line 6 - ncols를 통해 열람한 Sheet의 컬럼의 갯수를 확인 할 수 있습니다.

Line 7 - nrows를 통해 열람한 Sheet의 로우의 갯수를 확인 할 수 있습니다.

출력결과 아래와 같습니다.

-------- Sheet1 --------
Number of col: 4
Number of low: 4
-------- Sheet2 --------
Number of col: 2
Number of low: 2

3. Get values in excel file


__author__ = 'Administrator'
import xlrd
wb = xlrd.open_workbook("C:\\test.xlsx")
ws = wb.sheet_by_index(0)
ncol = ws.ncols
nlow = ws.nrows
print "-------- Sheet1 --------"
print "Number of col: " + str(ncol)
print "Number of low: " + str(nlow)
print "-------- Values of low --------"
i = 0
while i < nlow:
print str(ws.row_values(i))
i += 1
print "-------- Values of col --------"
i = 0
while i < ncol:
print str(ws.col_values(i))
i += 1
view rawgistfile1.txt hosted with ❤ by GitHub

row_values와 col_values를 통해 각 각 row와 col의 값을 구할 수 있습니다.

row_values(0)을 이용하면 엑셀의 1번 줄 [1A, 1B, 1C, 1D]를 출력 할 수 있습니다.

col_values(0)을 이용하면 엑셀의 A컬럼 [1A, 2A, 3A, 4A]를 출력 할 수 있습니다.

출력결과 아래와 같습니다.

-------- Sheet1 --------
Number of col: 4
Number of low: 4
-------- Values of low --------
[u'1A', u'1B', u'1C', u'1D']
[u'2A', u'2B', u'2C', u'2D']
[u'3A', u'3B', u'3C', u'3D']
[u'4A', u'4B', u'4C', u'4D']
-------- Values of col --------
[u'1A', u'2A', u'3A', u'4A']
[u'1B', u'2B', u'3B', u'4B']
[u'1C', u'2C', u'3C', u'4C']
[u'1D', u'2D', u'3D', u'4D']


4. values are saved the list


__author__ = 'Administrator'
import xlrd
wb = xlrd.open_workbook("C:\\test.xlsx")
ws = wb.sheet_by_index(0)
ncol = ws.ncols
nlow = ws.nrows
print "-------- Sheet1 --------"
print "Number of col: " + str(ncol)
print "Number of low: " + str(nlow)
print "-------- Values of Excel file --------"
i = 0
j = 0
low = []
list = []
while i < nlow :
while j < ncol :
low.append(str(ws.row_values(i)[j]))
j += 1
list.append(low)
low = []
i += 1
j = 0
i = 0
while i < 4 :
print list[i]
i += 1
view rawgistfile1.txt hosted with ❤ by GitHub

row_values(0)이 [1A, 1B, 1C, 1D]의 정보를 가지고 있습니다.

결론적으로 1A만 불러오려면 row_values(0)[0]을 이용하면 1A만 출력 할 수 있습니다.

이를 통해 Python의 list에 엑셀파일의 모든 컬럼이 가지고있는 값을 저장 할 수 있습니다.

출력결과 아래와 같습니다.

-------- Sheet1 --------
Number of col: 4
Number of low: 4
-------- Values of Excel file --------
['1A', '1B', '1C', '1D']
['2A', '2B', '2C', '2D']
['3A', '3B', '3C', '3D']
['4A', '4B', '4C', '4D']

반응형
반응형

출처: http://funnyksoo.blogspot.kr/2015/11/python-pxssh-ssh-connect-send-command.html


pxssh를 이용하면 ssh를 이용해 linux에 접속하여 직접 command를 날릴 수 있고, 반환값도 받아 올 수 있습니다.

먼저 pxssh를 이용하기위해 모듈 pexpect를 설치해줍니다.

# wget https://pypi.python.org/packages/source/p/pexpect/pexpect-4.0.1.tar.gz#md5=056df81e6ca7081f1015b4b147b977b7

# tar xvf pexpect-4.0.1.tar.gz

# cd pexpect-4.0.1.tar.gz

# python setup.py install

먼저 모듈을 아래와 같이 로드해줍니다.

from pexpect import pxssh

현재 파이썬 3.x버전을 사용하고 있으며, 간혹 책이나 튜토리얼을 보게되면

import pxssh 와 같이 선언하는 문구를 보실 수 있습니다.

그러나 위와 같이 선언시 import하지 못해 에러가 발생합니다.

s = pxssh.pxssh()를 통해 변수를 초기화 해 준 뒤 아래의 함수들을 이용하여 로그인 및 커맨드를 실행합니다.

s.login(Domain, ID, Password) - 로그인 관련 메소드로 해당 도메인에 해당 아이디와
 패스워드를 이용해 로그인 합니다.

s.sendline(Command) - 명령어를 실행하는 부분으로 Command에 입력된 명령어를 실행합니다.

s.prompt() - 실행된 명령어의 실행(return되는) 값을 받기 위해 사용합니다.

s.before.decode() - s.before에 실행된 명령어를 가지고 있고, 이를 decode()하여 출력합니다.


from pexpect import pxssh
s=pxssh.pxssh()
s.login('127.0.0.1', 'root', '123456')
s.sendline('uname -v')
s.prompt()
print (s.before.decode())
view rawpxssh hosted with ❤ by GitHub

위와 같은 코드를 완성하였습니다.

Line 4 - 127.0.0.1 도메인으로 root/123456 으로 로그인을 시도합니다.
(로그인 관련 리턴값을 받아 올 수 있습니다.)
Line 6 - uname -v 명령어를 실행합니다.
Line 8 - 받아온 값을 출력합니다.

실행 결과는 아래와 같습니다.

----------------------------------------------------------------
# python3 pxssh.py 
uname -v
#1 SMP Tue Nov 11 17:57:25 UTC 2014

----------------------------------------------------------------


반응형
반응형

출처 : https://github.com/GeneralMills/pytrends/blob/master/pytrends/pyGTrends.py


from __future__ import absolute_import, print_function, unicode_literals

import copy
import csv
from datetime import datetime
from io import open
import re
import sys
import requests
import json
from fake_useragent import UserAgent
if sys.version_info[0] == 2:  # Python 2
    from cookielib import CookieJar
    from cStringIO import StringIO
    from urllib import urlencode
    from urllib import quote
    from urllib2 import build_opener, HTTPCookieProcessor
else:  # Python 3
    from http.cookiejar import CookieJar
    from io import StringIO
    from urllib.parse import urlencode
    from urllib.parse import quote
    from urllib.request import build_opener, HTTPCookieProcessor


class pyGTrends(object):
    """
    Google Trends API
    """
    def __init__(self, username, password):
        """
        Initialize hard-coded URLs, HTTP headers, and login parameters
        needed to connect to Google Trends, then connect.
        """
        self.login_params = {
            'continue': 'http://www.google.com/trends',
            'PersistentCookie': 'yes',
            'Email': username,
            'Passwd': password}
        # provide fake user agent to look like a desktop brower
        self.fake_ua = UserAgent()
        self.headers = [
            ('Referrer', 'https://www.google.com/accounts/ServiceLoginBoxAuth'),
            ('Content-type', 'application/x-www-form-urlencoded'),
            ('User-Agent', self.fake_ua.chrome),
            ('Accept', 'text/plain')]
        self.url_ServiceLoginBoxAuth = 'https://accounts.google.com/ServiceLoginBoxAuth'
        self.url_Export = 'http://www.google.com/trends/trendsReport'
        self.url_CookieCheck = 'https://www.google.com/accounts/CheckCookie?chtml=LoginDoneHtml'
        self.url_PrefCookie = 'http://www.google.com'
        self._connect()

    def _connect(self):
        """
        Connect to Google Trends. Use cookies.
        """
        self.cj = CookieJar()
        self.opener = build_opener(HTTPCookieProcessor(self.cj))
        self.opener.addheaders = self.headers

        resp = self.opener.open(self.url_ServiceLoginBoxAuth).read()
        resp = re.sub(r'\s\s+', ' ', resp.decode(encoding='utf-8'))

        galx = re.compile('<input name="GALX"[\s]+type="hidden"[\s]+value="(?P<galx>[a-zA-Z0-9_-]+)">')
        m = galx.search(resp)
        if not m:
            galx = re.compile('<input type="hidden"[\s]+name="GALX"[\s]+value="(?P<galx>[a-zA-Z0-9_-]+)">')
            m = galx.search(resp)
            if not m:
                raise Exception('Cannot parse GALX out of login page')

        self.login_params['GALX'] = m.group('galx')
        params = urlencode(self.login_params).encode('utf-8')
        self.opener.open(self.url_ServiceLoginBoxAuth, params)
        self.opener.open(self.url_CookieCheck)
        self.opener.open(self.url_PrefCookie)

    def request_report(self, keywords, hl='en-US', cat=None, geo=None, date=None, tz=None, gprop=None):
        query_param = 'q=' + quote(keywords)

        # This logic handles the default of skipping parameters
        # Parameters that are set to '' will not filter the data requested.
        # See Readme.md for more information
        if cat is not None:
            cat_param = '&cat=' + cat
        else:
            cat_param = ''
        if date is not None:
            date_param = '&date=' + quote(date)
        else:
            date_param = ''
        if geo is not None:
            geo_param = '&geo=' + geo
        else:
            geo_param = ''
        if tz is not None:
            tz_param = '&tz=' + tz
        else:
            tz_param = ''
        if gprop is not None:
            gprop_param = '&gprop=' + gprop
        else:
            gprop_param = ''
        hl_param = '&hl=' + hl

        # These are the default parameters and shouldn't be changed.
        cmpt_param = "&cmpt=q"
        content_param = "&content=1"
        export_param = "&export=1"

        combined_params = query_param + cat_param + date_param + geo_param + hl_param + tz_param + cmpt_param \
                          + content_param + export_param + gprop_param

        print("Now downloading information for:")
        print("http://www.google.com/trends/trendsReport?" + combined_params)

        raw_data = self.opener.open("http://www.google.com/trends/trendsReport?" + combined_params).read()
        self.decode_data = raw_data.decode('utf-8')

        if self.decode_data in ["You must be signed in to export data from Google Trends"]:
            print("You must be signed in to export data from Google Trends")
            raise Exception(self.decode_data)

    def save_csv(self, path, trend_name):
        fileName = path + trend_name + ".csv"
        with open(fileName, mode='wb') as f:
            f.write(self.decode_data.encode('utf8'))

    def get_data(self):
        return self.decode_data

    def get_suggestions(self, keyword):
        kw_param = quote(keyword)
        raw_data = self.opener.open("https://www.google.com/trends/api/autocomplete/" + kw_param).read()
        # response is invalid json but if you strip off ")]}'," from the front it is then valid
        json_data = json.loads(raw_data[5:].decode())
        return json_data


def parse_data(data):
    """
    Parse data in a Google Trends CSV export (as `str`) into JSON format
    with str values coerced into appropriate Python-native objects.

    Parameters
    ----------
    data : str
        CSV data as text, output by `pyGTrends.get_data()`

    Returns
    -------
    parsed_data : dict of lists
        contents of `data` parsed into JSON form with appropriate Python types;
        sub-tables split into separate dict items, keys are sub-table "names",
        and data values parsed according to type, e.g.
        '10' => 10, '10%' => 10, '2015-08-06' => `datetime.datetime(2015, 8, 6, 0, 0)`
    """
    parsed_data = {}
    for i, chunk in enumerate(re.split(r'\n{2,}', data)):
        if i == 0:
            match = re.search(r'^(.*?) interest: (.*)\n(.*?); (.*?)$', chunk)
            if match:
                source, query, geo, period = match.groups()
                parsed_data['info'] = {'source': source, 'query': query,
                                       'geo': geo, 'period': period}
        else:
            chunk = _clean_subtable(chunk)
            rows = [row for row in csv.reader(StringIO(chunk)) if row]
            if not rows:
                continue
            label, parsed_rows = _parse_rows(rows)
            if label in parsed_data:
                parsed_data[label+'_1'] = parsed_data.pop(label)
                parsed_data[label+'_2'] = parsed_rows
            else:
                parsed_data[label] = parsed_rows

    return parsed_data


def _clean_subtable(chunk):
    """
    The data output by Google Trends is human-friendly, not machine-friendly;
    this function fixes a couple egregious data problems.
    1. Google replaces rising search percentages with "Breakout" if the increase
    is greater than 5000%: https://support.google.com/trends/answer/4355000 .
    For parsing's sake, we set it equal to that high threshold value.
    2. Rising search percentages between 1000 and 5000 have a comma separating
    the thousands, which is terrible for CSV data. We strip it out.
    """
    chunk = re.sub(r',Breakout', ',5000%', chunk)
    chunk = re.sub(r'(,[+-]?[1-4]),(\d{3}%\n)', r'\1\2', chunk)
    return chunk


def _infer_dtype(val):
    """
    Using regex, infer a limited number of dtypes for string `val`
    (only dtypes expected to be found in a Google Trends CSV export).
    """
    if re.match(r'\d{4}-\d{2}(?:-\d{2})?', val):
        return 'date'
    elif re.match(r'[+-]?\d+$', val):
        return 'int'
    elif re.match(r'[+-]?\d+%$', val):
        return 'pct'
    elif re.match(r'[a-zA-Z ]+', val):
        return 'text'
    else:
        msg = "val={0} dtype not recognized".format(val)
        raise ValueError(msg)


def _convert_val(val, dtype):
    """
    Convert string `val` into Python-native object according to its `dtype`:
    '10' => 10, '10%' => 10, '2015-08-06' => `datetime.datetime(2015, 8, 6, 0, 0)`,
    ' ' => None, 'foo' => 'foo'
    """
    if not val.strip():
        return None
    elif dtype == 'date':
        match = re.match(r'(\d{4}-\d{2}-\d{2})', val)
        if match:
            return datetime.strptime(match.group(), '%Y-%m-%d')
        else:
            return datetime.strptime(re.match(r'(\d{4}-\d{2})', val).group(), '%Y-%m')
    elif dtype == 'int':
        return int(val)
    elif dtype == 'pct':
        return int(val[:-1])
    else:
        return val


def _parse_rows(rows, header='infer'):
    """
    Parse sub-table `rows` into JSON form and convert str values into appropriate
    Python types; if `header` == `infer`, will attempt to infer if header row
    in rows, otherwise pass True/False.
    """
    if not rows:
        raise ValueError('rows={0} is invalid'.format(rows))
    rows = copy.copy(rows)
    label = rows[0][0].replace(' ', '_').lower()

    if header == 'infer':
        if len(rows) >= 3:
            if _infer_dtype(rows[1][-1]) != _infer_dtype(rows[2][-1]):
                header = True
            else:
                header = False
        else:
            header = False
    if header is True:
        colnames = rows[1]
        data_idx = 2
    else:
        colnames = None
        data_idx = 1

    data_dtypes = [_infer_dtype(val) for val in rows[data_idx]]
    if any(dd == 'pct' for dd in data_dtypes):
        label += '_pct'

    parsed_rows = []
    for row in rows[data_idx:]:
        vals = [_convert_val(val, dtype) for val, dtype in zip(row, data_dtypes)]
        if colnames:
            parsed_rows.append({colname:val for colname, val in zip(colnames, vals)})
        else:
            parsed_rows.append(vals)

    return label, parsed_rows

예제 코드




반응형
반응형

출처: http://blog.lyuwonkyung.com/windows-pipeseo-unicodedecodeerror-balsaeng-2/


센터에서 지원받아 사용하던 13인치 맥북을 반납하고, 내 개인 15인치 맥북은 사무실에 상주시키기로 하였기에 집에서는 다시 윈도우 노트북으로 작업을 하게 되었다. 고작 15개월간 맥으로 갈아타 개발을 했을 뿐인데 다시 돌아온 윈도우는 개발하기에 너무나도 불편하였다! (내가 유별난게 아닐것이다!) 결국 우분투를 설치해도 보았지만, Wine으로 카카오톡이나 멜론을 정상 실행할 수 없었기에 결국 다시 윈도우로는 와야하겠고.. (카톡만 잘 되었어도 그냥 버텼을텐데, 새로운 메시지가 오자마자 Crash가 터지는 이유를 도저히 알 수 없었다.) 이런 와중에 윈도우에 개발 환경을 다 세팅하고 Flask 개발을 위해 pip install Flask를 입력하는 순간 UnicodeDecodeError 예외가 나를 당황스럽게 만들었다.

물론 인터넷에 여러가지 해결책이 나와있지만, 그 해결책 각각들은 내게 도움이 되지 않았고, 간만에 아주 긴 삽질을 통해 두 가지의 아티클을 조합하여 문제를 해결하였다! (문제는 당연히도 비유니코드 문자열 이슈 때문인듯 하다. 아마도 경로에 들어있는 멀티바이트 문자 같은 것들 때문인듯.)

  1. Python이 설치된 경로(e.g. 나의 경우에는 C:\python)의 lib 디렉토리(윈도니까 폴더라고 해야하는 것인가)에 있는 site.py(c:\python\lib\site.py)를 열어 479, 490 라인의 asciiutf-8로 수정한다.

    def setencoding():
        """Set the string encoding used by the Unicode implementation.  The
        default is 'ascii', but if you're willing to experiment, you can
        change this."""
        encoding = "utf-8" # Default value set by _PyUnicode_Init() # 요기!
        if 0:
            # Enable to support locale aware default string encodings.
            import locale
            loc = locale.getdefaultlocale()
            if loc[1]:
                encoding = loc[1]
        if 0:
            # Enable to switch off string to Unicode coercion and implicit
            # Unicode to string conversion.
            encoding = "undefined"
        if encoding != "utf-8":  # 요기!
            # On Non-Unicode builds this will raise an AttributeError...
            sys.setdefaultencoding(encoding) # Needs Python Unicode build !
    
  2. 같은 디렉토리의 ntpath.py를 열어 87번째 라인의 p_pathp_path.encode('utf-8')로 치환해준다.

    ....
        elif p_drive and p_drive != result_drive:
            if p_drive.lower() != result_drive.lower():
                # Different drives => ignore the first path entirely
                result_drive = p_drive
                result_path = p_path
                continue
            # Same drive in different case
            result_drive = p_drive
        # Second path is relative to the first
        if result_path and result_path[-1] not in '\\/':
            result_path = result_path + '\\'
        result_path = result_path + p_path.encode('utf-8')  # 요기!
    ## add separator between UNC and non-absolute path
    if (result_path and result_path[0] not in '\\/' and
        result_drive and result_drive[-1:] != ':'):
        return result_drive + sep + result_path
    return result_drive + result_pat
    

이제 잘 될것이다!

반응형

+ Recent posts