แƒงแƒ•แƒ”แƒšแƒ Habr แƒ”แƒ แƒ— แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜

แฒกแƒแƒฆแƒแƒ›แƒ แƒ›แƒจแƒ•แƒ˜แƒ“แƒแƒ‘แƒ˜แƒกแƒ. 2 แƒฌแƒ”แƒšแƒ˜ แƒ’แƒแƒ•แƒ˜แƒ“แƒ แƒ แƒแƒช แƒ“แƒแƒ˜แƒฌแƒ”แƒ แƒ. แƒ‘แƒแƒšแƒ แƒกแƒขแƒแƒขแƒ˜แƒ Habr-แƒ˜แƒก แƒแƒœแƒแƒšแƒ˜แƒ–แƒ˜แƒก แƒจแƒ”แƒกแƒแƒฎแƒ”แƒ‘ แƒ“แƒ แƒ–แƒแƒ’แƒ˜แƒ”แƒ แƒ—แƒ˜ แƒžแƒฃแƒœแƒฅแƒขแƒ˜ แƒจแƒ”แƒ˜แƒชแƒ•แƒแƒšแƒ.

แƒ แƒแƒ“แƒ”แƒกแƒแƒช แƒ›แƒ˜แƒœแƒ“แƒแƒ“แƒ แƒ›แƒฅแƒแƒœแƒแƒ“แƒ Habr-แƒ˜แƒก แƒแƒกแƒšแƒ˜, แƒ’แƒแƒ“แƒแƒ•แƒฌแƒงแƒ•แƒ˜แƒขแƒ” แƒ“แƒแƒ›แƒ”แƒฌแƒ”แƒ แƒ แƒžแƒแƒ แƒกแƒ”แƒ แƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒจแƒ”แƒ˜แƒœแƒแƒฎแƒแƒ•แƒ“แƒ แƒแƒ•แƒขแƒแƒ แƒ”แƒ‘แƒ˜แƒก แƒ›แƒ—แƒ”แƒš แƒจแƒ˜แƒœแƒแƒแƒ แƒกแƒก แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜. แƒ แƒแƒ’แƒแƒ  แƒ›แƒแƒฎแƒ“แƒ แƒ“แƒ แƒ แƒ แƒจแƒ”แƒชแƒ“แƒแƒ›แƒ”แƒ‘แƒก แƒจแƒ”แƒ•แƒฎแƒ•แƒ“แƒ˜ - แƒจแƒ”แƒ’แƒ˜แƒซแƒšแƒ˜แƒแƒ— แƒฌแƒแƒ˜แƒ™แƒ˜แƒ—แƒฎแƒแƒ— แƒญแƒ แƒ˜แƒšแƒ˜แƒก แƒฅแƒ•แƒ”แƒจ.

TLDR- แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒ˜แƒก แƒ‘แƒ›แƒฃแƒšแƒ˜

แƒžแƒแƒ แƒกแƒ”แƒ แƒ˜แƒก แƒžแƒ˜แƒ แƒ•แƒ”แƒšแƒ˜ แƒ•แƒ”แƒ แƒกแƒ˜แƒ. แƒ”แƒ แƒ—แƒ˜ แƒ—แƒ”แƒ›แƒ, แƒ‘แƒ”แƒ•แƒ แƒ˜ แƒžแƒ แƒแƒ‘แƒšแƒ”แƒ›แƒ

แƒ“แƒแƒกแƒแƒฌแƒงแƒ˜แƒกแƒ˜แƒกแƒ—แƒ•แƒ˜แƒก, แƒ›แƒ” แƒ’แƒแƒ“แƒแƒ•แƒฌแƒงแƒ•แƒ˜แƒขแƒ” แƒจแƒ”แƒ›แƒ”แƒฅแƒ›แƒœแƒ แƒกแƒ™แƒ แƒ˜แƒžแƒขแƒ˜แƒก แƒžแƒ แƒแƒขแƒแƒขแƒ˜แƒžแƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒจแƒ˜แƒช แƒกแƒขแƒแƒขแƒ˜แƒ แƒ’แƒแƒœแƒ˜แƒฎแƒ˜แƒšแƒ”แƒ‘แƒ แƒ“แƒ แƒฉแƒแƒ›แƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ˜แƒกแƒ—แƒแƒœแƒแƒ•แƒ” แƒ’แƒแƒœแƒ—แƒแƒ•แƒกแƒ“แƒ”แƒ‘แƒ แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜. แƒแƒ แƒฏแƒ”แƒ  แƒ“แƒแƒคแƒ˜แƒฅแƒ แƒ”แƒ‘แƒ˜แƒก แƒ’แƒแƒ แƒ”แƒจแƒ” แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒ” sqlite3, แƒ แƒแƒ“แƒ’แƒแƒœ. แƒ”แƒก แƒ˜แƒงแƒ แƒœแƒแƒ™แƒšแƒ”แƒ‘แƒแƒ“ แƒจแƒ แƒแƒ›แƒแƒขแƒ”แƒ•แƒแƒ“แƒ˜: แƒแƒ  แƒ˜แƒงแƒ แƒกแƒแƒญแƒ˜แƒ แƒ แƒšแƒแƒ™แƒแƒšแƒฃแƒ แƒ˜ แƒกแƒ”แƒ แƒ•แƒ”แƒ แƒ˜แƒก แƒฅแƒแƒœแƒ, แƒจแƒ”แƒฅแƒ›แƒœแƒ˜แƒšแƒ˜-แƒฉแƒแƒœแƒ“แƒ-แƒฌแƒแƒจแƒšแƒ˜แƒšแƒ˜ แƒ“แƒ แƒ›แƒกแƒ’แƒแƒ•แƒกแƒ˜ แƒ แƒแƒ›.

one_thread.py

from bs4 import BeautifulSoup
import sqlite3
import requests
from datetime import datetime

def main(min, max):
    conn = sqlite3.connect('habr.db')
    c = conn.cursor()
    c.execute('PRAGMA encoding = "UTF-8"')
    c.execute("CREATE TABLE IF NOT EXISTS habr(id INT, author VARCHAR(255), title VARCHAR(255), content  TEXT, tags TEXT)")

    start_time = datetime.now()
    c.execute("begin")
    for i in range(min, max):
        url = "https://m.habr.com/post/{}".format(i)
        try:
            r = requests.get(url)
        except:
            with open("req_errors.txt") as file:
                file.write(i)
            continue
        if(r.status_code != 200):
            print("{} - {}".format(i, r.status_code))
            continue

        html_doc = r.text
        soup = BeautifulSoup(html_doc, 'html.parser')

        try:
            author = soup.find(class_="tm-user-info__username").get_text()
            content = soup.find(id="post-content-body")
            content = str(content)
            title = soup.find(class_="tm-article-title__text").get_text()
            tags = soup.find(class_="tm-article__tags").get_text()
            tags = tags[5:]
        except:
            author,title,tags = "Error", "Error {}".format(r.status_code), "Error"
            content = "ะŸั€ะธ ะฟะฐั€ัะธะฝะณะต ัั‚ะพะน ัั‚ั€ะฐะฝะธั†ะต ะฟั€ะพะธะทะพัˆะปะฐ ะพัˆะธะฑะบะฐ."

        c.execute('INSERT INTO habr VALUES (?, ?, ?, ?, ?)', (i, author, title, content, tags))
        print(i)
    c.execute("commit")
    print(datetime.now() - start_time)

main(1, 490406)

แƒงแƒ•แƒ”แƒšแƒแƒคแƒ”แƒ แƒ˜ แƒ™แƒšแƒแƒกแƒ˜แƒ™แƒฃแƒ แƒ˜แƒ - แƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ— Beautiful Soup-แƒก, แƒ•แƒ—แƒฎแƒแƒ•แƒ— แƒ“แƒ แƒกแƒฌแƒ แƒแƒคแƒ˜ แƒžแƒ แƒแƒขแƒแƒขแƒ˜แƒžแƒ˜ แƒ›แƒ–แƒแƒ“ แƒแƒ แƒ˜แƒก. แƒ”แƒก แƒฃแƒ‘แƒ แƒแƒšแƒแƒ“โ€ฆ

  • แƒ’แƒ•แƒ”แƒ แƒ“แƒ˜แƒก แƒฉแƒแƒ›แƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ แƒ”แƒ แƒ— แƒ—แƒ”แƒ›แƒแƒจแƒ˜แƒ

  • แƒ—แƒฃ แƒจแƒ”แƒฌแƒงแƒ•แƒ”แƒขแƒ— แƒกแƒ™แƒ แƒ˜แƒžแƒขแƒ˜แƒก แƒจแƒ”แƒกแƒ แƒฃแƒšแƒ”แƒ‘แƒแƒก, แƒ›แƒแƒจแƒ˜แƒœ แƒ›แƒ—แƒ”แƒšแƒ˜ แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒ แƒแƒ แƒกแƒแƒ“ แƒฌแƒแƒ•แƒ. แƒงแƒแƒ•แƒ”แƒšแƒ˜แƒ•แƒ” แƒแƒ›แƒ˜แƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’, แƒฉแƒแƒ“แƒ”แƒœแƒ แƒฎแƒแƒ แƒชแƒ˜แƒ”แƒšแƒ“แƒ”แƒ‘แƒ แƒ›แƒฎแƒแƒšแƒแƒ“ แƒงแƒ•แƒ”แƒšแƒ แƒ’แƒแƒแƒœแƒแƒšแƒ˜แƒ–แƒ”แƒ‘แƒ˜แƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’.
    แƒ แƒ แƒ—แƒฅแƒ›แƒ แƒฃแƒœแƒ“แƒ, แƒ—แƒฅแƒ•แƒ”แƒœ แƒจแƒ”แƒ’แƒ˜แƒซแƒšแƒ˜แƒแƒ— แƒจแƒ”แƒ˜แƒขแƒแƒœแƒแƒ— แƒชแƒ•แƒšแƒ˜แƒšแƒ”แƒ‘แƒ”แƒ‘แƒ˜ แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜ แƒงแƒแƒ•แƒ”แƒšแƒ˜ แƒฉแƒแƒกแƒ›แƒ˜แƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’, แƒ›แƒแƒ’แƒ แƒแƒ› แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒกแƒ™แƒ แƒ˜แƒžแƒขแƒ˜แƒก แƒจแƒ”แƒกแƒ แƒฃแƒšแƒ”แƒ‘แƒ˜แƒก แƒ“แƒ แƒ แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ•แƒœแƒแƒ“ แƒ’แƒแƒ˜แƒ–แƒ แƒ“แƒ”แƒ‘แƒ.

  • แƒžแƒ˜แƒ แƒ•แƒ”แƒšแƒ˜ 100 แƒกแƒขแƒแƒขแƒ˜แƒ˜แƒก แƒ’แƒแƒ แƒฉแƒ”แƒ•แƒ 000 แƒกแƒแƒแƒ—แƒ˜ แƒ“แƒแƒ›แƒญแƒ˜แƒ แƒ“แƒ.

แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒ•แƒžแƒแƒฃแƒšแƒแƒ‘ แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒšแƒ˜แƒก แƒกแƒขแƒแƒขแƒ˜แƒแƒก แƒ™แƒแƒ˜แƒœแƒขแƒ”แƒ’แƒ แƒ˜แƒ แƒ”แƒ‘แƒฃแƒšแƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒฌแƒแƒ•แƒ˜แƒ™แƒ˜แƒ—แƒฎแƒ” แƒ“แƒ แƒ•แƒ˜แƒžแƒแƒ•แƒ” แƒ แƒแƒ›แƒ“แƒ”แƒœแƒ˜แƒ›แƒ” แƒšแƒแƒ˜แƒค แƒฐแƒแƒ™แƒ˜ แƒแƒ› แƒžแƒ แƒแƒชแƒ”แƒกแƒ˜แƒก แƒ“แƒแƒกแƒแƒฉแƒฅแƒแƒ แƒ”แƒ‘แƒšแƒแƒ“:

  • Multithreading-แƒ˜แƒก แƒ’แƒแƒ›แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ แƒแƒฉแƒฅแƒแƒ แƒ”แƒ‘แƒก แƒ’แƒแƒ“แƒ›แƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒแƒก แƒ“แƒ แƒแƒ“แƒแƒ“แƒ แƒ.
  • แƒ—แƒฅแƒ•แƒ”แƒœ แƒจแƒ”แƒ’แƒ˜แƒซแƒšแƒ˜แƒแƒ— แƒ›แƒ˜แƒ˜แƒฆแƒแƒ— แƒแƒ แƒ แƒฐแƒแƒ‘แƒ แƒ˜แƒก แƒกแƒ แƒฃแƒšแƒ˜ แƒ•แƒ”แƒ แƒกแƒ˜แƒ, แƒแƒ แƒแƒ›แƒ”แƒ“ แƒ›แƒ˜แƒกแƒ˜ แƒ›แƒแƒ‘แƒ˜แƒšแƒฃแƒ แƒ˜ แƒ•แƒ”แƒ แƒกแƒ˜แƒ.
    แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“, แƒ—แƒฃ แƒ“แƒ”แƒกแƒ™แƒขแƒแƒžแƒ˜แƒก แƒ•แƒ”แƒ แƒกแƒ˜แƒแƒจแƒ˜ แƒ™แƒแƒ˜แƒœแƒขแƒ”แƒ’แƒ แƒ˜แƒ แƒ”แƒ‘แƒฃแƒšแƒ˜ แƒกแƒขแƒแƒขแƒ˜แƒ แƒ˜แƒฌแƒแƒœแƒ˜แƒก 378 แƒ™แƒ‘, แƒ›แƒแƒจแƒ˜แƒœ แƒ›แƒแƒ‘แƒ˜แƒšแƒฃแƒ แƒ˜ แƒ•แƒ”แƒ แƒกแƒ˜แƒแƒจแƒ˜ แƒ˜แƒก แƒฃแƒ™แƒ•แƒ” 126 แƒ™แƒ‘.

แƒ›แƒ”แƒแƒ แƒ” แƒ•แƒ”แƒ แƒกแƒ˜แƒ. แƒ‘แƒ”แƒ•แƒ แƒ˜ แƒ—แƒ”แƒ›แƒ, แƒ“แƒ แƒแƒ”แƒ‘แƒ˜แƒ—แƒ˜ แƒแƒ™แƒ แƒซแƒแƒšแƒ•แƒ แƒฐแƒแƒ‘แƒ แƒ˜แƒกแƒ’แƒแƒœ

แƒ แƒแƒ“แƒ”แƒกแƒแƒช แƒ˜แƒœแƒขแƒ”แƒ แƒœแƒ”แƒขแƒ˜ แƒ“แƒแƒ•แƒแƒ—แƒ•แƒแƒšแƒ˜แƒ”แƒ แƒ” แƒžแƒ˜แƒ—แƒแƒœแƒจแƒ˜ แƒ›แƒฃแƒšแƒขแƒ˜แƒ แƒ”แƒ“แƒ˜แƒœแƒ’แƒ˜แƒก แƒ—แƒ”แƒ›แƒแƒ–แƒ”, แƒแƒ•แƒ˜แƒ แƒฉแƒ˜แƒ” แƒฃแƒ›แƒแƒ แƒขแƒ˜แƒ•แƒ”แƒกแƒ˜ แƒ•แƒแƒ แƒ˜แƒแƒœแƒขแƒ˜ multiprocessing.dummy-แƒ˜แƒ—, แƒจแƒ”แƒ•แƒแƒ›แƒฉแƒœแƒ˜แƒ”, แƒ แƒแƒ› แƒžแƒ แƒแƒ‘แƒšแƒ”แƒ›แƒ”แƒ‘แƒ˜แƒช แƒ’แƒแƒฉแƒœแƒ“แƒ แƒ›แƒ แƒแƒ•แƒแƒšแƒ—แƒ แƒ”แƒแƒ“แƒ˜แƒ แƒ”แƒ‘แƒแƒกแƒ—แƒแƒœ แƒ”แƒ แƒ—แƒแƒ“.

SQLite3-แƒก แƒแƒ  แƒกแƒฃแƒ แƒก แƒ”แƒ แƒ—แƒ–แƒ” แƒ›แƒ”แƒข แƒซแƒแƒคแƒ—แƒแƒœ แƒ›แƒฃแƒจแƒแƒแƒ‘แƒ.
แƒ“แƒแƒคแƒ˜แƒฅแƒกแƒ˜แƒ แƒ“แƒ check_same_thread=False, แƒ›แƒแƒ’แƒ แƒแƒ› แƒ”แƒก แƒจแƒ”แƒชแƒ“แƒแƒ›แƒ แƒแƒ  แƒแƒ แƒ˜แƒก แƒ”แƒ แƒ—แƒแƒ“แƒ”แƒ แƒ—แƒ˜, แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜ แƒฉแƒแƒกแƒ›แƒ˜แƒก แƒ›แƒชแƒ“แƒ”แƒšแƒแƒ‘แƒ˜แƒกแƒแƒก แƒฎแƒแƒœแƒ“แƒแƒฎแƒแƒœ แƒฉแƒœแƒ“แƒ”แƒ‘แƒ แƒจแƒ”แƒชแƒ“แƒแƒ›แƒ”แƒ‘แƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ—แƒ แƒ›แƒแƒ’แƒ•แƒแƒ แƒ”แƒ‘แƒแƒช แƒ•แƒ”แƒ  แƒ›แƒแƒ•แƒแƒฎแƒ”แƒ แƒฎแƒ”.

แƒแƒ›แƒ˜แƒขแƒแƒ›, แƒ›แƒ” แƒ’แƒแƒ“แƒแƒ•แƒฌแƒงแƒ•แƒ˜แƒขแƒ” แƒฃแƒแƒ แƒ˜ แƒ—แƒฅแƒ•แƒแƒก แƒกแƒขแƒแƒขแƒ˜แƒ”แƒ‘แƒ˜แƒก แƒ›แƒงแƒ˜แƒกแƒ˜แƒ”แƒ แƒแƒ“ แƒฉแƒแƒกแƒ›แƒแƒ–แƒ” แƒžแƒ˜แƒ แƒ“แƒแƒžแƒ˜แƒ  แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜ แƒ“แƒ, แƒ’แƒแƒ•แƒ˜แƒฎแƒกแƒ”แƒœแƒ แƒ™แƒแƒ˜แƒœแƒขแƒ”แƒ’แƒ แƒ˜แƒ แƒ”แƒ‘แƒฃแƒšแƒ˜ แƒ’แƒแƒ“แƒแƒฌแƒงแƒ•แƒ”แƒขแƒ, แƒ’แƒแƒ“แƒแƒ•แƒฌแƒงแƒ•แƒ˜แƒขแƒ” แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒ แƒคแƒแƒ˜แƒšแƒ”แƒ‘แƒ˜, แƒ แƒแƒ“แƒ’แƒแƒœ แƒคแƒแƒ˜แƒšแƒจแƒ˜ แƒ›แƒ แƒแƒ•แƒแƒšแƒœแƒแƒ™แƒแƒ“แƒ˜แƒแƒœแƒ˜ แƒฉแƒแƒฌแƒ”แƒ แƒ˜แƒก แƒžแƒ แƒแƒ‘แƒšแƒ”แƒ›แƒ แƒแƒ  แƒแƒ แƒ˜แƒก.

แƒฐแƒแƒ‘แƒ แƒ˜ แƒ˜แƒฌแƒงแƒ”แƒ‘แƒก แƒแƒ™แƒ แƒซแƒแƒšแƒ•แƒแƒก แƒกแƒแƒ›แƒ–แƒ” แƒ›แƒ”แƒขแƒ˜ แƒ—แƒ”แƒ›แƒ˜แƒก แƒ’แƒแƒ›แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ˜แƒกแƒ—แƒ•แƒ˜แƒก.
แƒ’แƒแƒœแƒกแƒแƒ™แƒฃแƒ—แƒ แƒ”แƒ‘แƒ˜แƒ— แƒ’แƒฃแƒšแƒ›แƒแƒ“แƒ’แƒ˜แƒœแƒ” แƒ›แƒชแƒ“แƒ”แƒšแƒแƒ‘แƒแƒ› แƒฐแƒแƒ‘แƒ แƒจแƒ˜ แƒ’แƒแƒกแƒ•แƒšแƒ แƒจแƒ”แƒ˜แƒซแƒšแƒ”แƒ‘แƒ แƒ“แƒแƒกแƒ แƒฃแƒšแƒ“แƒ”แƒก ip แƒแƒ™แƒ แƒซแƒแƒšแƒ•แƒ˜แƒ— แƒ แƒแƒ›แƒ“แƒ”แƒœแƒ˜แƒ›แƒ” แƒกแƒแƒแƒ—แƒ˜แƒก แƒ’แƒแƒœแƒ›แƒแƒ•แƒšแƒแƒ‘แƒแƒจแƒ˜. แƒแƒกแƒ” แƒ แƒแƒ› แƒ—แƒฅแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ›แƒแƒ˜แƒงแƒ”แƒœแƒแƒ— แƒ›แƒฎแƒแƒšแƒแƒ“ 3 แƒ—แƒ”แƒ›แƒ, แƒ›แƒแƒ’แƒ แƒแƒ› แƒ”แƒก แƒฃแƒ™แƒ•แƒ” แƒ™แƒแƒ แƒ’แƒ˜แƒ, แƒ แƒแƒ“แƒ’แƒแƒœ 100-แƒ–แƒ” แƒ›แƒ”แƒขแƒ˜ แƒกแƒขแƒแƒขแƒ˜แƒ˜แƒก แƒ’แƒแƒ›แƒ”แƒแƒ แƒ”แƒ‘แƒ˜แƒก แƒ“แƒ แƒ แƒ›แƒชแƒ˜แƒ แƒ“แƒ”แƒ‘แƒ 26-แƒ“แƒแƒœ 12 แƒฌแƒแƒ›แƒแƒ›แƒ“แƒ”.

แƒแƒฆแƒกแƒแƒœแƒ˜แƒจแƒœแƒแƒ•แƒ˜แƒ, แƒ แƒแƒ› แƒ”แƒก แƒ•แƒ”แƒ แƒกแƒ˜แƒ แƒกแƒแƒ™แƒ›แƒแƒแƒ“ แƒแƒ แƒแƒกแƒขแƒแƒ‘แƒ˜แƒšแƒฃแƒ แƒ˜แƒ แƒ“แƒ แƒฉแƒแƒ›แƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ”แƒ‘แƒ˜ แƒžแƒ”แƒ แƒ˜แƒแƒ“แƒฃแƒšแƒแƒ“ แƒ˜แƒจแƒšแƒ”แƒ‘แƒ แƒกแƒขแƒแƒขแƒ˜แƒ”แƒ‘แƒ˜แƒก แƒ“แƒ˜แƒ“ แƒ แƒแƒแƒ“แƒ”แƒœแƒแƒ‘แƒแƒ–แƒ”.

async_v1.py

from bs4 import BeautifulSoup
import requests
import os, sys
import json
from multiprocessing.dummy import Pool as ThreadPool
from datetime import datetime
import logging

def worker(i):
    currentFile = "files\{}.json".format(i)

    if os.path.isfile(currentFile):
        logging.info("{} - File exists".format(i))
        return 1

    url = "https://m.habr.com/post/{}".format(i)

    try: r = requests.get(url)
    except:
        with open("req_errors.txt") as file:
            file.write(i)
        return 2

    # ะ—ะฐะฟะธััŒ ะทะฐะฑะปะพะบะธั€ะพะฒะฐะฝะฝั‹ั… ะทะฐะฟั€ะพัะพะฒ ะฝะฐ ัะตั€ะฒะตั€
    if (r.status_code == 503):
        with open("Error503.txt", "a") as write_file:
            write_file.write(str(i) + "n")
            logging.warning('{} / 503 Error'.format(i))

    # ะ•ัะปะธ ะฟะพัั‚ะฐ ะฝะต ััƒั‰ะตัั‚ะฒัƒะตั‚ ะธะปะธ ะพะฝ ะฑั‹ะป ัะบั€ั‹ั‚
    if (r.status_code != 200):
        logging.info("{} / {} Code".format(i, r.status_code))
        return r.status_code

    html_doc = r.text
    soup = BeautifulSoup(html_doc, 'html5lib')

    try:
        author = soup.find(class_="tm-user-info__username").get_text()

        timestamp = soup.find(class_='tm-user-meta__date')
        timestamp = timestamp['title']

        content = soup.find(id="post-content-body")
        content = str(content)
        title = soup.find(class_="tm-article-title__text").get_text()
        tags = soup.find(class_="tm-article__tags").get_text()
        tags = tags[5:]

        # ะœะตั‚ะบะฐ, ั‡ั‚ะพ ะฟะพัั‚ ัะฒะปัะตั‚ัั ะฟะตั€ะตะฒะพะดะพะผ ะธะปะธ ั‚ัƒั‚ะพั€ะธะฐะปะพะผ.
        tm_tag = soup.find(class_="tm-tags tm-tags_post").get_text()

        rating = soup.find(class_="tm-votes-score").get_text()
    except:
        author = title = tags = timestamp = tm_tag = rating = "Error" 
        content = "ะŸั€ะธ ะฟะฐั€ัะธะฝะณะต ัั‚ะพะน ัั‚ั€ะฐะฝะธั†ะต ะฟั€ะพะธะทะพัˆะปะฐ ะพัˆะธะฑะบะฐ."
        logging.warning("Error parsing - {}".format(i))
        with open("Errors.txt", "a") as write_file:
            write_file.write(str(i) + "n")

    # ะ—ะฐะฟะธัั‹ะฒะฐะตะผ ัั‚ะฐั‚ัŒัŽ ะฒ json
    try:
        article = [i, timestamp, author, title, content, tm_tag, rating, tags]
        with open(currentFile, "w") as write_file:
            json.dump(article, write_file)
    except:
        print(i)
        raise

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print("ะะตะพะฑั…ะพะดะธะผั‹ ะฟะฐั€ะฐะผะตั‚ั€ั‹ min ะธ max. ะ˜ัะฟะพะปัŒะทะพะฒะฐะฝะธะต: async_v1.py 1 100")
        sys.exit(1)
    min = int(sys.argv[1])
    max = int(sys.argv[2])

    # ะ•ัะปะธ ะฟะพั‚ะพะบะพะฒ >3
    # ั‚ะพ ั…ะฐะฑั€ ะฑะฐะฝะธั‚ ipัˆะฝะธะบ ะฝะฐ ะฒั€ะตะผั
    pool = ThreadPool(3)

    # ะžั‚ัั‡ะตั‚ ะฒั€ะตะผะตะฝะธ, ะทะฐะฟัƒัะบ ะฟะพั‚ะพะบะพะฒ
    start_time = datetime.now()
    results = pool.map(worker, range(min, max))

    # ะŸะพัะปะต ะทะฐะบั€ั‹ั‚ะธั ะฒัะตั… ะฟะพั‚ะพะบะพะฒ ะฟะตั‡ะฐั‚ะฐะตะผ ะฒั€ะตะผั
    pool.close()
    pool.join()
    print(datetime.now() - start_time)

แƒ›แƒ”แƒกแƒแƒ›แƒ” แƒ•แƒ”แƒ แƒกแƒ˜แƒ. แƒกแƒแƒ‘แƒแƒšแƒแƒ

แƒ›แƒ”แƒแƒ แƒ” แƒ•แƒ”แƒ แƒกแƒ˜แƒ˜แƒก แƒ’แƒแƒ›แƒแƒ แƒ—แƒ•แƒ˜แƒกแƒแƒก แƒแƒฆแƒ›แƒแƒ•แƒแƒฉแƒ˜แƒœแƒ”, แƒ แƒแƒ› Habr-แƒก, แƒฃแƒ”แƒชแƒ แƒแƒ“, แƒแƒฅแƒ•แƒก API, แƒ แƒแƒ›แƒ”แƒšแƒกแƒแƒช แƒกแƒแƒ˜แƒขแƒ˜แƒก แƒ›แƒแƒ‘แƒ˜แƒšแƒฃแƒ แƒ˜ แƒ•แƒ”แƒ แƒกแƒ˜แƒ แƒฌแƒ•แƒ“แƒ”แƒ‘แƒ. แƒ˜แƒก แƒฃแƒคแƒ แƒ แƒกแƒฌแƒ แƒแƒคแƒแƒ“ แƒ˜แƒขแƒ•แƒ˜แƒ แƒ—แƒ”แƒ‘แƒ, แƒ•แƒ˜แƒ“แƒ แƒ” แƒ›แƒแƒ‘แƒ˜แƒšแƒฃแƒ แƒ˜ แƒ•แƒ”แƒ แƒกแƒ˜แƒ, แƒ แƒแƒ“แƒ’แƒแƒœ แƒ”แƒก แƒแƒ แƒ˜แƒก แƒ›แƒฎแƒแƒšแƒแƒ“ json, แƒ แƒแƒ›แƒšแƒ˜แƒก แƒ’แƒแƒแƒœแƒแƒšแƒ˜แƒ–แƒ”แƒ‘แƒแƒช แƒ™แƒ˜ แƒแƒ  แƒแƒ แƒ˜แƒก แƒกแƒแƒญแƒ˜แƒ แƒ. แƒ‘แƒแƒšแƒแƒก แƒ’แƒแƒ“แƒแƒ•แƒฌแƒงแƒ•แƒ˜แƒขแƒ” แƒ˜แƒกแƒ”แƒ• แƒ’แƒแƒ“แƒแƒ›แƒ”แƒฌแƒ”แƒ แƒ แƒฉแƒ”แƒ›แƒ˜ แƒกแƒชแƒ”แƒœแƒแƒ แƒ˜.

แƒแƒกแƒ” แƒ แƒแƒ›, แƒ˜แƒžแƒแƒ•แƒ แƒ”แƒก แƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ˜ API, แƒจแƒ”แƒ’แƒ˜แƒซแƒšแƒ˜แƒแƒ— แƒ“แƒแƒ˜แƒฌแƒงแƒแƒ— แƒ›แƒ˜แƒกแƒ˜ แƒ’แƒแƒ แƒฉแƒ”แƒ•แƒ.

async_v2.py

import requests
import os, sys
import json
from multiprocessing.dummy import Pool as ThreadPool
from datetime import datetime
import logging

def worker(i):
    currentFile = "files\{}.json".format(i)

    if os.path.isfile(currentFile):
        logging.info("{} - File exists".format(i))
        return 1

    url = "https://m.habr.com/kek/v1/articles/{}/?fl=ru%2Cen&hl=ru".format(i)

    try:
        r = requests.get(url)
        if r.status_code == 503:
            logging.critical("503 Error")
            return 503
    except:
        with open("req_errors.txt") as file:
            file.write(i)
        return 2

    data = json.loads(r.text)

    if data['success']:
        article = data['data']['article']

        id = article['id']
        is_tutorial = article['is_tutorial']
        time_published = article['time_published']
        comments_count = article['comments_count']
        lang = article['lang']
        tags_string = article['tags_string']
        title = article['title']
        content = article['text_html']
        reading_count = article['reading_count']
        author = article['author']['login']
        score = article['voting']['score']

        data = (id, is_tutorial, time_published, title, content, comments_count, lang, tags_string, reading_count, author, score)
        with open(currentFile, "w") as write_file:
            json.dump(data, write_file)

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print("ะะตะพะฑั…ะพะดะธะผั‹ ะฟะฐั€ะฐะผะตั‚ั€ั‹ min ะธ max. ะ˜ัะฟะพะปัŒะทะพะฒะฐะฝะธะต: asyc.py 1 100")
        sys.exit(1)
    min = int(sys.argv[1])
    max = int(sys.argv[2])

    # ะ•ัะปะธ ะฟะพั‚ะพะบะพะฒ >3
    # ั‚ะพ ั…ะฐะฑั€ ะฑะฐะฝะธั‚ ipัˆะฝะธะบ ะฝะฐ ะฒั€ะตะผั
    pool = ThreadPool(3)

    # ะžั‚ัั‡ะตั‚ ะฒั€ะตะผะตะฝะธ, ะทะฐะฟัƒัะบ ะฟะพั‚ะพะบะพะฒ
    start_time = datetime.now()
    results = pool.map(worker, range(min, max))

    # ะŸะพัะปะต ะทะฐะบั€ั‹ั‚ะธั ะฒัะตั… ะฟะพั‚ะพะบะพะฒ ะฟะตั‡ะฐั‚ะฐะตะผ ะฒั€ะตะผั
    pool.close()
    pool.join()
    print(datetime.now() - start_time)

แƒ˜แƒก แƒจแƒ”แƒ˜แƒชแƒแƒ•แƒก แƒ•แƒ”แƒšแƒ”แƒ‘แƒก, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒ˜แƒช แƒ“แƒแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ”แƒ‘แƒฃแƒšแƒ˜แƒ แƒ แƒแƒ’แƒแƒ แƒช แƒ—แƒแƒ•แƒแƒ“ แƒกแƒขแƒแƒขแƒ˜แƒแƒกแƒ—แƒแƒœ, แƒแƒกแƒ”แƒ•แƒ” แƒแƒ•แƒขแƒแƒ แƒ—แƒแƒœ, แƒ•แƒ˜แƒœแƒช แƒ˜แƒก แƒ“แƒแƒฌแƒ”แƒ แƒ.

API.png

แƒงแƒ•แƒ”แƒšแƒ Habr แƒ”แƒ แƒ— แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜

แƒ›แƒ” แƒแƒ  แƒ’แƒแƒ“แƒแƒ•แƒแƒ’แƒ“แƒ” แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒกแƒขแƒแƒขแƒ˜แƒ˜แƒก แƒกแƒ แƒฃแƒšแƒ˜ json, แƒ›แƒแƒ’แƒ แƒแƒ› แƒจแƒ”แƒ•แƒ˜แƒœแƒแƒฎแƒ” แƒ›แƒฎแƒแƒšแƒแƒ“ แƒ˜แƒก แƒ•แƒ”แƒšแƒ”แƒ‘แƒ˜, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒ˜แƒช แƒ›แƒญแƒ˜แƒ แƒ“แƒ”แƒ‘แƒแƒ“แƒ:

  • id
  • แƒแƒ แƒ˜แƒก_แƒขแƒฃแƒขแƒแƒ แƒ˜แƒแƒšแƒ˜
  • แƒ“แƒ แƒ_แƒ’แƒแƒ›แƒแƒฅแƒ•แƒ”แƒงแƒœแƒ”แƒ‘แƒฃแƒšแƒ˜
  • แƒกแƒแƒ—แƒแƒฃแƒ แƒ˜
  • แƒจแƒ˜แƒœแƒแƒแƒ แƒกแƒ˜
  • แƒ™แƒแƒ›แƒ”แƒœแƒขแƒแƒ แƒ”แƒ‘แƒ˜_แƒ—แƒ•แƒšแƒ
  • lang แƒแƒ แƒ˜แƒก แƒ”แƒœแƒ, แƒ แƒแƒ›แƒ”แƒšแƒ–แƒ”แƒช แƒ˜แƒฌแƒ”แƒ แƒ”แƒ‘แƒ แƒกแƒขแƒแƒขแƒ˜แƒ. แƒฏแƒ”แƒ แƒฏแƒ”แƒ แƒแƒ‘แƒ˜แƒ— แƒ›แƒแƒก แƒ›แƒฎแƒแƒšแƒแƒ“ en แƒ“แƒ ru แƒแƒฅแƒ•แƒก.
  • tags_string - แƒงแƒ•แƒ”แƒšแƒ แƒขแƒ”แƒ’แƒ˜ แƒžแƒแƒกแƒขแƒ˜แƒ“แƒแƒœ
  • reading_count
  • แƒแƒ•แƒขแƒแƒ แƒ˜
  • แƒฅแƒฃแƒšแƒ โ€” แƒกแƒขแƒแƒขแƒ˜แƒ˜แƒก แƒ แƒ”แƒ˜แƒขแƒ˜แƒœแƒ’แƒ˜.

แƒแƒ›แƒ แƒ˜แƒ’แƒแƒ“, API-แƒก แƒ’แƒแƒ›แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ˜แƒ—, แƒกแƒ™แƒ แƒ˜แƒžแƒขแƒ˜แƒก แƒจแƒ”แƒกแƒ แƒฃแƒšแƒ”แƒ‘แƒ˜แƒก แƒ“แƒ แƒ แƒจแƒ”แƒ•แƒแƒ›แƒชแƒ˜แƒ แƒ” 8 แƒฌแƒแƒ›แƒแƒ›แƒ“แƒ” 100 url-แƒ–แƒ”.

แƒ›แƒแƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒ แƒแƒช แƒฉแƒแƒ›แƒแƒ•แƒขแƒ•แƒ˜แƒ แƒ—แƒแƒ•แƒ— แƒกแƒแƒญแƒ˜แƒ แƒ แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ”แƒ‘แƒก, แƒฃแƒœแƒ“แƒ แƒ“แƒแƒ•แƒแƒ›แƒฃแƒจแƒแƒ•แƒแƒ— แƒ“แƒ แƒจแƒ”แƒ•แƒ˜แƒงแƒ•แƒแƒœแƒแƒ— แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜. แƒแƒ แƒช แƒ›แƒ” แƒ›แƒฅแƒแƒœแƒ˜แƒ แƒžแƒ แƒแƒ‘แƒšแƒ”แƒ›แƒ:

parser.py

import json
import sqlite3
import logging
from datetime import datetime

def parser(min, max):
    conn = sqlite3.connect('habr.db')
    c = conn.cursor()
    c.execute('PRAGMA encoding = "UTF-8"')
    c.execute('PRAGMA synchronous = 0') # ะžั‚ะบะปัŽั‡ะฐะตะผ ะฟะพะดั‚ะฒะตั€ะถะดะตะฝะธะต ะทะฐะฟะธัะธ, ั‚ะฐะบ ัะบะพั€ะพัั‚ัŒ ัƒะฒะตะปะธั‡ะธะฒะฐะตั‚ัั ะฒ ั€ะฐะทั‹.
    c.execute("CREATE TABLE IF NOT EXISTS articles(id INTEGER, time_published TEXT, author TEXT, title TEXT, content TEXT, 
    lang TEXT, comments_count INTEGER, reading_count INTEGER, score INTEGER, is_tutorial INTEGER, tags_string TEXT)")
    try:
        for i in range(min, max):
            try:
                filename = "files\{}.json".format(i)
                f = open(filename)
                data = json.load(f)

                (id, is_tutorial, time_published, title, content, comments_count, lang,
                 tags_string, reading_count, author, score) = data

                # ะ ะฐะดะธ ะปัƒั‡ัˆะตะน ั‡ะธั‚ะฐะตะผะพัั‚ะธ ะฑะฐะทั‹ ะผะพะถะฝะพ ะฟั€ะตะฝะตะฑั€ะตั‡ัŒ ั‡ะธั‚ะฐะตะผะพัั‚ัŒัŽ ะบะพะดะฐ. ะ˜ะปะธ ะฝะตั‚?
                # ะ•ัะปะธ ะฒะฐะผ ั‚ะฐะบ ะบะฐะถะตั‚ัั, ะผะพะถะฝะพ ะฟั€ะพัั‚ะพ ะทะฐะผะตะฝะธั‚ัŒ ะบะพั€ั‚ะตะถ ะฐั€ะณัƒะผะตะฝั‚ะพะผ data. ะ ะตัˆะฐั‚ัŒ ะฒะฐะผ.

                c.execute('INSERT INTO articles VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', (id, time_published, author,
                                                                                        title, content, lang,
                                                                                        comments_count, reading_count,
                                                                                        score, is_tutorial,
                                                                                        tags_string))
                f.close()

            except IOError:
                logging.info('FileNotExists')
                continue

    finally:
        conn.commit()

start_time = datetime.now()
parser(490000, 490918)
print(datetime.now() - start_time)

แƒกแƒขแƒแƒขแƒ˜แƒกแƒขแƒ˜แƒ™แƒ

แƒ˜แƒกแƒ”, แƒขแƒ แƒแƒ“แƒ˜แƒชแƒ˜แƒฃแƒšแƒแƒ“, แƒกแƒแƒ‘แƒแƒšแƒแƒแƒ“, แƒจแƒ”แƒ’แƒ˜แƒซแƒšแƒ˜แƒแƒ— แƒแƒ›แƒแƒ˜แƒฆแƒแƒ— แƒ แƒแƒ›แƒ“แƒ”แƒœแƒ˜แƒ›แƒ” แƒกแƒขแƒแƒขแƒ˜แƒกแƒขแƒ˜แƒ™แƒ แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ”แƒ‘แƒ˜แƒ“แƒแƒœ:

  • แƒ›แƒแƒกแƒแƒšแƒแƒ“แƒœแƒ”แƒšแƒ˜ 490 แƒฉแƒแƒ›แƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ˜แƒกแƒ’แƒแƒœ, แƒ›แƒฎแƒแƒšแƒแƒ“ 406 แƒกแƒขแƒแƒขแƒ˜แƒ แƒ˜แƒงแƒ แƒ’แƒแƒ“แƒ›แƒแƒฌแƒ”แƒ แƒ˜แƒšแƒ˜. แƒ’แƒแƒ›แƒแƒ“แƒ˜แƒก, แƒ แƒแƒ› Habrรฉ-แƒ–แƒ” แƒกแƒขแƒแƒขแƒ˜แƒ”แƒ‘แƒ˜แƒก แƒœแƒแƒฎแƒ”แƒ•แƒแƒ แƒ–แƒ” แƒ›แƒ”แƒขแƒ˜ (228) แƒ“แƒแƒ›แƒแƒšแƒฃแƒšแƒ˜ แƒแƒœ แƒฌแƒแƒจแƒšแƒ˜แƒšแƒ˜ แƒ˜แƒงแƒ.
  • แƒ›แƒ—แƒ”แƒšแƒ˜ แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒ, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒจแƒ”แƒ“แƒ’แƒ”แƒ‘แƒ แƒ—แƒ˜แƒ—แƒฅแƒ›แƒ˜แƒก แƒœแƒแƒฎแƒ”แƒ•แƒแƒ แƒ˜ แƒ›แƒ˜แƒšแƒ˜แƒแƒœแƒ˜ แƒกแƒขแƒแƒขแƒ˜แƒ˜แƒกแƒ’แƒแƒœ, แƒ˜แƒฌแƒแƒœแƒ˜แƒก 2.95 แƒ’แƒ‘. แƒจแƒ”แƒ™แƒฃแƒ›แƒจแƒฃแƒšแƒ˜ แƒคแƒแƒ แƒ›แƒ˜แƒ— - 495 แƒ›แƒ‘.
  • แƒกแƒแƒ”แƒ แƒ—แƒ แƒฏแƒแƒ›แƒจแƒ˜, Habrรฉ-แƒ˜แƒก แƒแƒ•แƒขแƒแƒ แƒ˜ 37804 แƒแƒ“แƒแƒ›แƒ˜แƒแƒœแƒ˜แƒ. แƒจแƒ”แƒ’แƒแƒฎแƒกแƒ”แƒœแƒ”แƒ‘แƒ—, แƒ แƒแƒ› แƒ”แƒก แƒกแƒขแƒแƒขแƒ˜แƒกแƒขแƒ˜แƒ™แƒ แƒ›แƒฎแƒแƒšแƒแƒ“ แƒšแƒแƒ˜แƒ• แƒžแƒแƒกแƒขแƒ”แƒ‘แƒ˜แƒ“แƒแƒœ แƒแƒ แƒ˜แƒก.
  • แƒงแƒ•แƒ”แƒšแƒแƒ–แƒ” แƒžแƒ แƒแƒ“แƒฃแƒฅแƒขแƒ˜แƒฃแƒšแƒ˜ แƒแƒ•แƒขแƒแƒ แƒ˜ แƒฐแƒแƒ‘แƒ แƒ”แƒ–แƒ” - แƒแƒšแƒ˜แƒ–แƒแƒ แƒ˜ - 8774 แƒกแƒขแƒแƒขแƒ˜แƒ.
  • แƒงแƒ•แƒ”แƒšแƒแƒ–แƒ” แƒ แƒ”แƒ˜แƒขแƒ˜แƒœแƒ’แƒฃแƒšแƒ˜ แƒกแƒขแƒแƒขแƒ˜แƒ - 1448 แƒžแƒšแƒฃแƒกแƒ˜
  • แƒงแƒ•แƒ”แƒšแƒแƒ–แƒ” แƒฌแƒแƒ™แƒ˜แƒ—แƒฎแƒฃแƒšแƒ˜ แƒกแƒขแƒแƒขแƒ˜แƒ โ€” 1660841 แƒœแƒแƒฎแƒ•แƒ
  • แƒงแƒ•แƒ”แƒšแƒแƒ–แƒ” แƒ’แƒแƒœแƒฎแƒ˜แƒšแƒฃแƒšแƒ˜ แƒกแƒขแƒแƒขแƒ˜แƒ โ€” 2444 แƒ™แƒแƒ›แƒ”แƒœแƒขแƒแƒ แƒ˜

แƒ˜แƒกแƒ”, แƒขแƒแƒžแƒ”แƒ‘แƒ˜แƒก แƒกแƒแƒฎแƒ˜แƒ—แƒขแƒแƒž 15 แƒแƒ•แƒขแƒแƒ แƒ˜แƒงแƒ•แƒ”แƒšแƒ Habr แƒ”แƒ แƒ— แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜
แƒขแƒแƒž 15 แƒ แƒ”แƒ˜แƒขแƒ˜แƒœแƒ’แƒ˜แƒ—แƒงแƒ•แƒ”แƒšแƒ Habr แƒ”แƒ แƒ— แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜
แƒฌแƒแƒ™แƒ˜แƒ—แƒฎแƒฃแƒšแƒ˜ แƒขแƒแƒž 15แƒงแƒ•แƒ”แƒšแƒ Habr แƒ”แƒ แƒ— แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜
แƒ’แƒแƒœแƒฎแƒ˜แƒšแƒฃแƒšแƒ˜ แƒขแƒแƒž 15แƒงแƒ•แƒ”แƒšแƒ Habr แƒ”แƒ แƒ— แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜

แƒฌแƒงแƒแƒ แƒ: www.habr.com

แƒแƒฎแƒแƒšแƒ˜ แƒ™แƒแƒ›แƒ”แƒœแƒขแƒแƒ แƒ˜แƒก แƒ“แƒแƒ›แƒแƒขแƒ”แƒ‘แƒ