Python snippet: Thu thập dữ liệu

souping_oreilly

Trước khi có thể làm việc với dữ liệu, việc đầu tiên bạn cần làm là thu thập chúng. Có rất nhiều nguồn dữ liệu khác nhau như web, APIs, databases, những định dạng file plain text (.csv, .tsv). Sau khi thu thập, ta có thể thực hiện vài động tác chuẩn hoá dữ liệu sao cho phù hợp với nhu cầu làm việc của mình nhất.

Tiếp tục series Python snippet (Python snippet: Visualizing), tuần này tôi sẽ đưa vào một vài snippet thường gặp trong quá trình thu thập dữ liệu.
Source code: data-science-works
Thư viện: csv, json, re, collections, requests, bs4, twython

TSV

TSV là viết tắt của Tab Separated Values. Đây là định dạng file trong đó dữ liệu ngăn cách nhau bởi ký tự Tab. Ví dụ bên dưới sẽ đọc vào một file .tsv và xuất dữ liệu ra ngoài màn hình.

Input: tab_delimited_stock_prices.tsv

Nguồn thu thập: http://s.cafef.vn/du-lieu.chn

Snippet:

import csv
def print_data(ma_ck, kl, gia, delta):
    print ma_ck, "#", kl, "#", gia, "#", delta

with open('data/tab_delimited_stock_prices.tsv', 'rb') as f:
    reader = csv.reader(f, delimiter='\t')
    for row in reader:
        ma_ck = row[0]
        kl = row[1]
        gia = float(row[2])
        delta = row[3]
        print_data(ma_ck, kl, gia, delta)

Output:

## TAB delimited stock prices
TV2 # 45,012 # 147.4 # +13.4 (+10.00%)
CTT # 100 # 6.6 # +0.6 (+10.00%)
PCE # 100 # 16.6 # +1.5 (+9.93%)
HAT # 13,300 # 73.2 # +6.6 (+9.87%)

CSV

CSV là viết tắt của Colon/Comma Separated Values. Đây là định dạng file trong đó dữ liệu ngăn cách nhau bởi ký tự “:” hoặc “,”. Ví dụ bên dưới sẽ đọc vào một file .csv và xuất dữ liệu ra ngoài màn hình hoặc một file .csv khác.

Input: colon_delimited_stock_prices.csv

Nguồn thu thập: http://s.cafef.vn/du-lieu.chn

Snippet:

import csv
def print_data(ma_ck, kl, gia, delta):
    print ma_ck, "#", kl, "#", gia, "#", delta

with open('data/colon_delimited_stock_prices.csv', 'rb') as f:
    reader = csv.DictReader(f, delimiter=':')
    for row in reader:
        ma_ck = row["MA_CK"]
        kl = row["KL"]
        gia = float(row["GIA"])
        delta = row["DELTA"]
        print_data(ma_ck, kl, gia, delta)

print "## WRITING out comma_delimited_stock_prices.csv"
today_prices = {'VCF': 152.4, 'VAF': 13.3, 'ATA': 0.8}
with open('data/comma_delimited_stock_prices.csv', 'wb') as f:
    writer = csv.writer(f, delimiter=',')
    for stock, price in today_prices.items():
        writer.writerow([stock, price])

Output: comma_delimited_stock_prices.csv

## COLON delimited stock prices
TV2 # 45,012 # 147.4 # +13.4 (+10.00%)
CTT # 100 # 6.6 # +0.6 (+10.00%)
PCE # 100 # 16.6 # +1.5 (+9.93%)
HAT # 13,300 # 73.2 # +6.6 (+9.87%)

JSON

JSON là viết tắt của JavaScript Object Notation. Đây là kiểu dữ liệu rất thường được sử dụng trong phát triển web. Đặc biệt là các APIs RESTful do tính tiện lợi trong cài đặt và dễ dàng trong parsing dữ liệu. Dưới đây là một ví dụ đơn giản, đọc lên một file .json và lấy ra một giá trị của dữ liệu.

Input: colors.json

Snippets:

import json
with open("data/colors.json") as json_data:
    document = json.load(json_data)
    print "Getting blue value:", document["blue"]

Output:

## PARSING json
Getting blue value: #00f

Github API

Ta có thể vọc nhiều hơn với JSON thông qua Github API. Giả sử bạn có các repos trên Github, bạn có thể sử dụng Github API để tải về thông tin của những repos này dưới định dạng JSON. Nhiệm vụ của bạn là rút ra một vài thông tin hữu ích sau đó xuất ra màn hình.

Snippet:

import json
import requests
from dateutil.parser import parse
from collections import Counter

endpoint = "https://api.github.com/users/ongxuanhong/repos"
repos = json.loads(requests.get(endpoint).text)

dates = [parse(repo["created_at"]) for repo in repos]
month_counts = Counter(date.month for date in dates)
weekday_counts = Counter(date.weekday() for date in dates)

print "dates", [d.strftime("%d/%m/%y") for d in dates]
print "month_counts", month_counts
print "weekday_count", weekday_counts

last_5_repositories = sorted(repos,
                             key=lambda r: r["created_at"],
                             reverse=True)[:5]

print "last five repos", [repo["name"]
                          for repo in last_5_repositories]

Output:

## GitHub API
dates ['08/12/15', '25/08/15', '24/08/15', '07/07/16', '27/08/15', '16/10/16', '31/08/15', '23/08/16', '08/12/15', '21/05/16', '10/10/16', '06/10/15', '05/07/15', '21/03/16', '02/10/16', '07/12/15', '01/09/15', '03/09/15', '20/08/15', '22/11/15', '30/01/16', '05/03/16', '17/09/15', '17/09/15', '28/06/16', '20/04/16', '29/08/15']
month_counts Counter({8: 7, 9: 4, 10: 4, 12: 3, 3: 2, 7: 2, 1: 1, 4: 1, 5: 1, 6: 1, 11: 1})
weekday_count Counter({1: 7, 3: 6, 0: 5, 5: 4, 6: 4, 2: 1})
last five repos [u'data-science-works', u'java-snippets', u'kse-2016', u'hmm', u'aws-dsp-analysis']

Crawling Oreilly books

oreilly_website

Các trang web là một trong những nguồn dữ liệu đa dạng và phong phú nhất. Bạn có thể viết các hàm crawling để thu thập dữ liệu. Trong ví dụ này, ta sẽ vào trang bán sách của Oreilly. Ta có thể điều hướng và duyệt danh sách trực tiếp qua URL nhờ vào tham số &page=[1,2,3,…].

Trong hàm scrap(), Crawler của chúng ta sẽ duyệt qua từng trang để lấy thông tin của các đầu sách (title, authors, isbn, date). Cuối cùng, ta sẽ thống kê số lượng sách cho từng năm và xuất ra biểu đồ cột để so sánh.

import requests, re
import matplotlib.pyplot as plt
from bs4 import BeautifulSoup
from collections import Counter

def is_video(td):
    """it's a video if it has exactly one pricelabel, and if
    the stripped text inside that pricelabel starts with 'Video'"""
    price_labels = td('span', 'pricelabel')
    return (len(price_labels) == 1 and
            price_labels[0].text.strip().startswith("Video"))

def book_info(td):
    """given a BeautifulSoup Tag representing a book,
    extract the book's details and return a dict"""

    title = td.find("div", "thumbheader").a.text
    by_author = td.find('div', 'AuthorName').text
    authors = [x.strip() for x in re.sub("^By ", "", by_author).split(",")]
    isbn_link = td.find("div", "thumbheader").a.get("href")
    isbn = re.match("/product/(.*)\.do", isbn_link).groups()[0]
    date = td.find("span", "directorydate").text.strip()

    return {
        "title": title,
        "authors": authors,
        "isbn": isbn,
        "date": date
    }

def scrape(num_pages=10):
    base_url = "http://shop.oreilly.com/category/browse-subjects/data.do?sortby=publicationDate&page="

    books = []

    for page_num in range(1, num_pages + 1):
        print "souping page", page_num
        url = base_url + str(page_num)
        soup = BeautifulSoup(requests.get(url).text, 'lxml')

        for td in soup('td', 'thumbtext'):
            if not is_video(td):
                books.append(book_info(td))

    return books

def get_year(book):
    """book["date"] looks like 'November 2016' so we need to
    split on the space and then take the second piece"""
    return int(book["date"].split()[1])

def plot_years(plt, books):
    # 2016 is the last complete year of data (when I ran this)
    year_counts = Counter(get_year(book) for book in books
                          if get_year(book) & <= 2016)

    years = sorted(year_counts)
    book_counts = [year_counts[year] for year in years]
    plt.bar([x - 0.5 for x in years], book_counts)
    plt.xlabel("year")
    plt.ylabel("# of data books")
    plt.title("Data is Big!")
    plt.show()

books = scrape()
plot_years(plt, books)

Output:

## Oreilly books
souping page 1
souping page 2
souping page 3
souping page 4
souping page 5
souping page 6
souping page 7
souping page 8
souping page 9
souping page 10

Twitter search API

Twitter cũng cung cấp cho ta API để tìm kiếm các status trên mạng xã hội này. Nhờ vào dữ liệu thu thập được, các nhà phân tích có thể dựa vào đây để đưa ra những khám phá hay những dự đoán thú vị như cuộc bầu cử tổng thống Mĩ ai đang là người được nhiều sự ủng hộ, hay dự báo thời tiết dựa vào trạng thái tâm lý của người dùng trong cộng đồng, … Ví dụ bên dưới chỉ đơn giản tìm kiếm các status có chứa từ khoá “data science” và in ra các trạng thái và tên người dùng tương ứng với kết quả tìm kiếm.

from twython import Twython

CONSUMER_KEY = "JeuEwD5RJiBbxiw9jTMBYBEmU"
CONSUMER_SECRET = "xRcmv8AMnSSMwq875HiP1SKFfGw51M97BvVH341yckPY3iilCu"
ACCESS_TOKEN = "47319754-NL1AIh9PBomIVsJe5HXB9vjE5y1rjwZFYUQx0odzo"
ACCESS_TOKEN_SECRET = "kcq7ER8UZSykDomPn9lYdh5DAafndvp73PzSfykTq0Kp7"

def call_twitter_search_api():
    twitter = Twython(CONSUMER_KEY, CONSUMER_SECRET)

    # search for tweets containing the phrase "data science"
    for status in twitter.search(q='"data science"')["statuses"]:
        user = status["user"]["screen_name"].encode('utf-8')
        text = status["text"].encode('utf-8')
        print user, ":", text
        print

call_twitter_search_api()

# generating hash
import hashlib
hash_object = hashlib.sha256(b'app_favorite_name')
hex_dig = hash_object.hexdigest()
print(hex_dig)

Output:

## Twitter search
NikiEmbers : RT @BuyBookstore: A collection of Data Science Interview Questions S https://t.co/Nm8tplRFNm #amreading #mondaymotivation

KatStilesAuthor : RT @BuyBookstore: A collection of Data Science Interview Questions S https://t.co/Nm8tplRFNm #amreading #mondaymotivation

careersingrowth : A Career You Can’t Ignore – #Data #Science https://t.co/BKGQVRWO0q

codearmster : RT @bicorner: Driving Value With #DataScience https://t.co/9SYEbrHwVu https://t.co/SG36fSrgjQ

bicorner : Driving Value With #DataScience https://t.co/9SYEbrHwVu https://t.co/SG36fSrgjQ

Joyce_Stack : Data Science track today will be held at 3:05 pm. We have some great talks on managing your data layer. Come along #APIStrat

badc0da : "Upcoming Meetings in Analytics, Big Data, Data Mining, Data Science: November and Beyond" https://t.co/xy6l47AkP3

Joyce_Stack : RT @wiredferret: Tomorrow at 3 PM, I'm speaking on The Death of Data at @apistrat #apistrat as part of the Data Science track.

lisachwinter : RT @ThoBoDo: A good start in Data Science is also to begin with approachable Analytics. Start doing is better than still Talking https://t.…

megu19g3 : RT @IBMBluemix: Wrap your mind around the new data-science tools in Bluemix: Manipulating #NoSQL data with #Python. https://t.co/pWtdesJNFo…

lc0d3r : That's data-driven approach! - Hacking my infant twins’ sleep with machine learning and data science
https://t.co/blriwO3nm9 #DataScience

accaminero : RT @analyticbridge: Answers to dozens of data science job interview questions https://t.co/O5OZT65V7I

michaelyoungMBN : RT @KrissHampton: Latest production for @DataLabScotland promoting their data science bootcamp https://t.co/6CGHZrjqwb #videoproduction #Fi…

AxiomtekUK : Data Science for Internet of Things (IoT) : Ten Differences From Traditional Data Science - https://t.co/9Tim5RKjeT

thm10004353 : RT @IBMBluemix: Wrap your mind around the new data-science tools in Bluemix: Manipulating #NoSQL data with #Python. https://t.co/pWtdesJNFo…
Advertisement

Một suy nghĩ 4 thoughts on “Python snippet: Thu thập dữ liệu

Trả lời

Điền thông tin vào ô dưới đây hoặc nhấn vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s