рд╕рдмреИ Habr рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдорд╛

рд╢реБрдн рджрд┐рдЙрдБрд╕реЛред рдпреЛ рд▓реЗрдЦрд┐рдПрдХреЛ реи рд╡рд░реНрд╖ рднрдпреЛред рдЕрдиреНрддрд┐рдо рд▓реЗрдЦ 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)

рд╕рдмреИ рдХреБрд░рд╛ рдХреНрд▓рд╛рд╕рд┐рдХ рдЫ - рд╣рд╛рдореА рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдЫреМрдВ рд╕реБрдиреНрджрд░ рд╕реВрдк, рдЕрдиреБрд░реЛрдзрд╣рд░реВ рд░ рджреНрд░реБрдд рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рддрдпрд╛рд░ рдЫред рддреНрдпреЛ рдорд╛рддреНрд░тАж

  • рдкреГрд╖реНрда рдбрд╛рдЙрдирд▓реЛрдб рдПрдЙрдЯреИ рдереНрд░реЗрдбрдорд╛ рдЫ

  • рдпрджрд┐ рддрдкрд╛рдИрдВрд▓реЗ рд╕реНрдХреНрд░рд┐рдкреНрдЯрдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдирдорд╛ рдЕрд╡рд░реЛрдз рдЧрд░реНрдиреБрднрдпреЛ рднрдиреЗ, рд╕рдореНрдкреВрд░реНрдг рдбрд╛рдЯрд╛рдмреЗрд╕ рдХрддреИ рдЬрд╛рдиреЗрдЫреИрдиред рдЖрдЦрд┐рд░, рдХрдорд┐рдЯ рд╕рдмреИ рдкрд╛рд░реНрд╕рд┐рдЩ рдкрдЫрд┐ рдорд╛рддреНрд░ рдЧрд░рд┐рдиреНрдЫред
    рдЕрд╡рд╢реНрдп рдкрдирд┐, рддрдкрд╛рдЗрдБ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкрдЫрд┐ рдбрд╛рдЯрд╛рдмреЗрд╕рдорд╛ рдкрд░рд┐рд╡рд░реНрддрдирд╣рд░реВ рдЧрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫ, рддрд░ рддреНрдпрд╕рдкрдЫрд┐ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕рдордп рдЙрд▓реНрд▓реЗрдЦрдиреАрдп рд░реВрдкрдорд╛ рдмрдвреНрдиреЗрдЫред

  • рдкрд╣рд┐рд▓реЛ 100 рд▓реЗрдЦрд╣рд░реВ рдкрд╛рд░реНрд╕ рдЧрд░реНрди рдорд▓рд╛рдИ 000 рдШрдгреНрдЯрд╛ рд▓рд╛рдЧреНрдпреЛред

рдЕрд░реНрдХреЛ рдо рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛рдХреЛ рд▓реЗрдЦ рдлреЗрд▓рд╛ рдкрд╛рд░реНрдЫреБ рдПрдХреАрдХреГрдд, рдЬреБрди рдореИрд▓реЗ рдкрдвреЗрдВ рд░ рдпрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛рд▓рд╛рдИ рдЧрддрд┐ рджрд┐рди рдХреЗрд╣реА рдЬреАрд╡рди рд╣реНрдпрд╛рдХрд╣рд░реВ рдлреЗрд▓рд╛ рдкрд╛рд░реЗ:

  • рдорд▓реНрдЯрд┐рдереНрд░реЗрдбрд┐рдЩ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджрд╛ рдХрд╣рд┐рд▓реЗрдХрд╛рд╣реАрдБ рдбрд╛рдЙрдирд▓реЛрдбрдХреЛ рдЧрддрд┐ рдмрдвреНрдЫред
  • рддрдкрд╛рдИрдВрд▓реЗ habr рдХреЛ рдкреВрд░реНрдг рд╕рдВрд╕реНрдХрд░рдг рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрди, рддрд░ рдпрд╕рдХреЛ рдореЛрдмрд╛рдЗрд▓ рд╕рдВрд╕реНрдХрд░рдгред
    рдЙрджрд╛рд╣рд░рдгрдХрд╛ рд▓рд╛рдЧрд┐, рдпрджрд┐ рдбреЗрд╕реНрдХрдЯрдк рд╕рдВрд╕реНрдХрд░рдгрдорд╛ рдПрдХ рдПрдХреАрдХреГрдд рд▓реЗрдЦрдХреЛ рд╡рдЬрди 378 KB рдЫ рднрдиреЗ, рдореЛрдмрд╛рдЗрд▓ рд╕рдВрд╕реНрдХрд░рдгрдорд╛ рдпреЛ рдкрд╣рд┐рд▓реЗ рдиреИ 126 KB рдЫред

рджреЛрд╕реНрд░реЛ рд╕рдВрд╕реНрдХрд░рдгред рдзреЗрд░реИ рдереНрд░реЗрдбрд╣рд░реВ, рд╣рдмреНрд░рдмрд╛рдЯ рдЕрд╕реНрдерд╛рдпреА рдкреНрд░рддрд┐рдмрдиреНрдз

рдЬрдм рдореИрд▓реЗ рдкрд╛рдЗрдердирдорд╛ рдорд▓реНрдЯрд┐рдереНрд░реЗрдбрд┐рдЩрдХреЛ рд╡рд┐рд╖рдпрдорд╛ рдЗрдиреНрдЯрд░рдиреЗрдЯрдХреЛ рдЦреЛрдЬреА рдЧрд░реЗрдБ, рдореИрд▓реЗ multiprocessing.dummy рдХреЛ рд╕рд╛рдердорд╛ рд╕рдмреИрднрдиреНрджрд╛ рд╕рд░рд▓ рд╡рд┐рдХрд▓реНрдк рд░реЛрдЬреЗрдВ, рдореИрд▓реЗ рдорд▓реНрдЯрд┐рдереНрд░реЗрдбрд┐рдЩрд╕рдБрдЧреИ рд╕рдорд╕реНрдпрд╛рд╣рд░реВ рджреЗрдЦрд╛ рдкрд░реЗрдХреЛ рджреЗрдЦреЗрдБред

SQLite3 рдПрдХ рднрдиреНрджрд╛ рдмрдвреА рдереНрд░реЗрдбрд╕рдБрдЧ рдХрд╛рдо рдЧрд░реНрди рдЪрд╛рд╣рдБрджреИрди.
рдирд┐рд╢реНрдЪрд┐рдд check_same_thread=False, рддрд░ рдпреЛ рддреНрд░реБрдЯрд┐ рдорд╛рддреНрд░ рд╣реЛрдЗрди, рдбрд╛рдЯрд╛рдмреЗрд╕рдорд╛ рд╕рдореНрдорд┐рд▓рд┐рдд рдЧрд░реНрдиреЗ рдкреНрд░рдпрд╛рд╕ рдЧрд░реНрджрд╛, рдХрд╣рд┐рд▓реЗрдХрд╛рд╣реАрдБ рддреНрд░реБрдЯрд┐рд╣рд░реВ рд╣реБрдиреНрдЫрдиреН рдЬреБрди рдореИрд▓реЗ рд╕рдорд╛рдзрд╛рди рдЧрд░реНрди рд╕рдХрд┐рдиред

рддрд╕рд░реНрде, рдо рдбрд╛рдЯрд╛рдмреЗрд╕рдорд╛ рд╕рд┐рдзреИ рд▓реЗрдЦрд╣рд░реВрдХреЛ рддрддреНрдХрд╛рд▓ рд╕рдореНрдорд┐рд▓рди рддреНрдпрд╛рдЧреНрди рдирд┐рд░реНрдгрдп рдЧрд░реНрдЫреБ рд░, рд╕рд╣рдмрджреНрдз рд╕рдорд╛рдзрд╛рди рд╕рдореНрдЭреЗрд░, рдо рдлрд╛рдЗрд▓рд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдирд┐рд░реНрдгрдп рдЧрд░реНрдЫреБ, рдХрд┐рдирдХрд┐ рдлрд╛рдЗрд▓рдорд╛ рдмрд╣реБ-рдереНрд░реЗрдбреЗрдб рд▓реЗрдЦрдирдорд╛ рдХреБрдиреИ рд╕рдорд╕реНрдпрд╛ рдЫреИрдиред

Habr рд▓реЗ рддреАрди рднрдиреНрджрд╛ рдмрдвреА рдереНрд░реЗрдбрд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрди рдкреНрд░рддрд┐рдмрдиреНрдз рдЧрд░реНрди рдерд╛рд▓реНрдЫ.
рд╡рд┐рд╢реЗрд╖ рдЧрд░реА Habr рдорд╛ рдЬрд╛рдирдХреЛ рд▓рд╛рдЧрд┐ рдЬреЛрд╕рд┐рд▓реЛ рдкреНрд░рдпрд╛рд╕рд╣рд░реВ рдХреЗрд╣реА рдШрдгреНрдЯрд╛рдХреЛ рд▓рд╛рдЧрд┐ 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
  • is_tutorial
  • рд╕рдордп_рдкреНрд░рдХрд╛рд╢рд┐рдд
  • рд╢реАрд░реНрд╖рдХ
  • рд╕рд╛рдордЧреНрд░реА
  • рдЯрд┐рдкреНрдкрдгреА_рдЧрдгрдирд╛
  • lang рднрдиреЗрдХреЛ рд▓реЗрдЦ рд▓реЗрдЦрд┐рдПрдХреЛ рднрд╛рд╖рд╛ рд╣реЛред рдЕрд╣рд┐рд▓реЗрд╕рдореНрдо, рдпреЛ рдХреЗрд╡рд▓ en рд░ ru рдЫред
  • tags_string - рдкреЛрд╕реНрдЯрдмрд╛рдЯ рд╕рдмреИ рдЯреНрдпрд╛рдЧрд╣рд░реВ
  • рдкрдвреНрдиреЗ_рдЧрдгрдирд╛
  • рд▓реЗрдЦрдХ
  • рдЕрдВрдХ - рд▓реЗрдЦ рдореВрд▓реНрдпрд╛рдЩреНрдХрдиред

рдпрд╕рд░реА, рдПрдкреАрдЖрдИ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░, рдореИрд▓реЗ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕рдордпрд▓рд╛рдИ 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 рдПрдордмреАред
  • рдХреБрд▓рдорд╛, 37804 рдорд╛рдирд┐рд╕рд╣рд░реВ Habr├й рдХреЛ рд▓реЗрдЦрдХ рд╣реБрдиреНред рдо рддрдкрд╛рдИрдВрд▓рд╛рдИ рд╕рдореНрдЭрд╛рдЙрдБрдЫреБ рдХрд┐ рдпреА рддрдереНрдпрд╛рдЩреНрдХрд╣рд░реВ рдкреНрд░рддреНрдпрдХреНрд╖ рдкреЛрд╕реНрдЯрд╣рд░реВрдмрд╛рдЯ рдорд╛рддреНрд░ рд╣реБрдиреНред
  • Habr├й рдорд╛ рд╕рдмреИрднрдиреНрджрд╛ рдЙрддреНрдкрд╛рджрдХ рд▓реЗрдЦрдХ - alizar - 8774 рд▓реЗрдЦред
  • рд╢реАрд░реНрд╖ рдореВрд▓реНрдпрд╛рдЩреНрдХрди рд▓реЗрдЦ - 1448 рдкреНрд▓рд╕
  • рд╕рдмреИрднрдиреНрджрд╛ рдзреЗрд░реИ рдкрдврд┐рдПрдХреЛ рд▓реЗрдЦ тАУ 1660841 рднреНрдпреВ
  • рдзреЗрд░реИ рдЪрд░реНрдЪрд╛ рдЧрд░рд┐рдПрдХреЛ рд▓реЗрдЦ - 2444 рдЯрд┐рдкреНрдкрдгреАрд╣рд░реВ

рдЦреИрд░, рд╢реАрд░реНрд╖ рдХреЛ рд░реВрдк рдорд╛рд╢реАрд░реНрд╖ 15 рд▓реЗрдЦрдХрд╣рд░реВрд╕рдмреИ Habr рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдорд╛
рдореВрд▓реНрдпрд╛рдЩреНрдХрди рджреНрд╡рд╛рд░рд╛ рд╢реАрд░реНрд╖ 15рд╕рдмреИ Habr рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдорд╛
рд╢реАрд░реНрд╖ 15 рдкрдвреНрдиреБрд╣реЛрд╕реНрд╕рдмреИ Habr рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдорд╛
рд╢реАрд░реНрд╖ 15 рдЫрд▓рдлрд▓ рдЧрд░рд┐рдпреЛрд╕рдмреИ Habr рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдорд╛

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдердкреНрди