بعد له غرمه مو پخیر. له لیکلو یې دوه کاله تېر شول.
کله چې ما غوښتل د حبر یوه کاپي ولرم، ما پریکړه وکړه چې یو پارسر ولیکم چې د لیکوالانو ټول مینځپانګې ډیټابیس ته خوندي کړي. دا څنګه پیښ شوي او زه له کومو غلطیو سره مخ شوم - تاسو کولی شئ د کټ لاندې ولولئ.
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 ساعته وخت واخیست.
بل زه د کاروونکي مقاله ومومم
- د ملټي تریډینګ کارول په وختونو کې د ډاونلوډ سرعت زیاتوي.
- تاسو د هابر بشپړ نسخه نه ترلاسه کولی شئ ، مګر د دې ګرځنده نسخه.
د مثال په توګه، که په ډیسټاپ نسخه کې یو همغږي مقاله 378 KB وزن ولري، نو په ګرځنده نسخه کې دا دمخه 126 KB دی.
دویمه نسخه. ډیری تارونه، د حبر څخه لنډمهاله بندیز
کله چې ما په python کې د ملټي تھریډینګ موضوع باندې انټرنیټ وټاکه ، ما د multiprocessing.dummy سره خورا ساده اختیار غوره کړ ، ما ولیدل چې د ملټي ریډینګ سره ستونزې څرګندې شوې.
SQLite3 نه غواړي له یو څخه ډیر تار سره کار وکړي.
ثابت check_same_thread=False
، مګر دا تېروتنه یوازینۍ نه ده ، کله چې ډیټابیس ته د ننوتلو هڅه کیږي ، ځینې وختونه غلطۍ رامینځته کیږي چې زه نشم حل کولی.
له همدې امله ، زه پریکړه کوم چې مستقیم ډیټابیس ته د مقالو سمدستي داخلول پریږدم او د یوځای شوي حل په یادولو سره ، زه پریکړه کوم چې فایلونه وکاروم ، ځکه چې فایل ته د څو اړخیزو لیکلو سره کومه ستونزه شتون نلري.
حبر له دریو څخه زیاتو تارونو کارولو بندیز پیل کوي.
په ځانګړي توګه هابر ته د رسیدو په زړه پورې هڅې کولی شي د څو ساعتونو لپاره د آی پی بندیز سره پای ته ورسیږي. نو تاسو باید یوازې 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 دی ، کوم چې حتی تحلیل کولو ته اړتیا نلري. په پای کې، ما پریکړه وکړه چې خپل سکریپټ بیا بیا ولیکم.
نو، موندل
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
ما د هرې مقالې بشپړ json ډمپ نه کړ، مګر یوازې هغه ساحې خوندي کړې چې زه ورته اړتیا لرم:
- id
- is_tutorial
- وخت_کابل شوی
- سرليک
- محتوا
- نظرونه_شمیر
- lang هغه ژبه ده چې مقاله پکې لیکل کیږي. تر اوسه پورې، دا یوازې en او ru لري.
- tags_string - د پوسټ څخه ټول ټګونه
- لوستل_ شمېرنه
- لیکوال
- نمرې - د مقالې درجه بندي.
پدې توګه ، د API په کارولو سره ، ما د سکریپټ اجرا کولو وخت په هر 8 یو آر ایل کې 100 ثانیو ته راکم کړ.
وروسته لدې چې موږ هغه ډیټا ډاونلوډ کړو چې موږ ورته اړتیا لرو ، موږ اړتیا لرو چې دا پروسس کړو او ډیټابیس ته یې دننه کړو. ما په دې کې هم کومه ستونزه نه درلوده:
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 مقالې ډاونلوډ شوي. دا معلومه شوه چې د هابري په اړه له نیمایي څخه ډیر (228) مقالې پټ یا حذف شوي.
- ټول ډیټابیس چې نږدې نیم ملیون مقالې لري، 2.95 GB وزن لري. په کمپریس شوي شکل کې - 495 MB.
- په مجموع کې، 37804 خلک د Habré لیکوالان دي. زه تاسو ته یادونه کوم چې دا احصایې یوازې د ژوندي پوسټونو څخه دي.
- په هابري کې ترټولو ګټور لیکوال -
علیزر - 8774 مقالې. غوره درجه شوې مقاله - 1448 پلسډیری لوستل شوي مقاله — 1660841 لیدنېډیری بحث شوی مقاله - 2444 تبصرې
ښه، د سرونو په بڼه15 غوره لیکوالان
د درجه بندي له مخې غوره 15
غوره 15 لوستل
پورته 15 بحث شوی
سرچینه: www.habr.com