جيڪڏهن توهان اسڪرپٽ جي عمل کي روڪيو، ته پوء سڄو ڊيٽابيس ڪٿي به نه ويندو. سڀ کان پوء، انجام صرف سڀني تجزيي کان پوء انجام ڏنو ويندو آهي.
يقينن، توهان هر داخل ٿيڻ کانپوءِ ڊيٽابيس ۾ تبديليون ڪري سگهو ٿا، پر پوءِ اسڪرپٽ جي عمل جو وقت گهڻو وڌي ويندو.
پهرين 100 مضمونن کي پارس ڪرڻ ۾ مون کي 000 ڪلاڪ لڳا.
اڳيون مون کي صارف جو مضمون ڳوليو گڏيل، جنهن کي مون پڙهيو ۽ هن عمل کي تيز ڪرڻ لاءِ ڪجهه لائف هيڪس ڏٺا:
ملٽي ٿريڊنگ استعمال ڪرڻ وقت تي ڊائون لوڊ ڪرڻ جي رفتار کي تيز ڪري ٿو.
توهان حاصل ڪري سگهو ٿا habr جو مڪمل نسخو نه، پر ان جو موبائل نسخو.
مثال طور، جيڪڏهن ڊيسڪ ٽاپ ورزن ۾ هڪ گڏيل مضمون جو وزن 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 آهي، جنهن کي پارس ڪرڻ جي به ضرورت ناهي. آخر ۾، مون فيصلو ڪيو ته منهنجي اسڪرپٽ ٻيهر ٻيهر لکان.
تنهن ڪري، دريافت ڪيو هي ڪڙي 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
مون هر مضمون جي مڪمل json کي ڊمپ نه ڪيو، پر صرف انهن شعبن کي محفوظ ڪيو جنهن جي مون کي ضرورت هئي:
id
is_tutorial
time_published
عنوان
مواد
تبصرو_ شمار
lang اها ٻولي آهي جنهن ۾ مضمون لکيو ويندو آهي. هينئر تائين، اهو صرف en ۽ ru آهي.
tags_string - پوسٽ مان سڀ ٽيگ
پڙهائي_ ڳڻپ
ليکڪ
سکور - آرٽيڪل جي درجه بندي.
اهڙيء طرح، 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)