আমি কীভাবে দ্রুত স্ক্র্যাপ করব


16

এখানে কাজটি এমন কোনও এপিআইকে স্ক্র্যাপ করা যা কোনও সাইট থেকে শুরু https://xxx.xxx.xxx/xxx/1.jsonহয় https://xxx.xxx.xxx/xxx/1417749.jsonএবং একে একে ঠিক মংডবতে লিখতে। তার জন্য আমার কাছে নিম্নলিখিত কোড রয়েছে:

client = pymongo.MongoClient("mongodb://127.0.0.1:27017")
db = client["thread1"]
com = db["threadcol"]
start_time = time.time()
write_log = open("logging.log", "a")
min = 1
max = 1417749
for n in range(min, max):
    response = requests.get("https:/xx.xxx.xxx/{}.json".format(str(n)))
    if response.status_code == 200:
        parsed = json.loads(response.text)
        inserted = com.insert_one(parsed)
        write_log.write(str(n) + "\t" + str(inserted) + "\n")
        print(str(n) + "\t" + str(inserted) + "\n")
write_log.close()

তবে টাস্কটি করতে অনেক সময় নিচ্ছে। আমি এখানে এই প্রক্রিয়াটি কীভাবে গতি বাড়িয়ে তুলতে পারি তা এখানে প্রশ্ন।


আপনি কি প্রথমবার বেঞ্চমার্ক করার চেষ্টা করেছিলেন যে একক জসনকে প্রক্রিয়া করতে কত সময় লাগে? এটি রেকর্ড প্রতি 300 মিমি লাগে তা ধরে নিলে, আপনি প্রায় 5 দিনের মধ্যে ক্রমান্বয়ে এই সমস্ত রেকর্ডটি প্রক্রিয়া করতে পারেন।
tuxdna

উত্তর:


5

যদি আপনি মাল্টি থ্রেডিং ব্যবহার করতে না চান তবে অ্যাসিনসিওও একটি সমাধান

import time
import pymongo
import json
import asyncio
from aiohttp import ClientSession


async def get_url(url, session):
    async with session.get(url) as response:
        if response.status == 200:
            return await response.text()


async def create_task(sem, url, session):
    async with sem:
        response = await get_url(url, session)
        if response:
            parsed = json.loads(response)
            n = url.rsplit('/', 1)[1]
            inserted = com.insert_one(parsed)
            write_log.write(str(n) + "\t" + str(inserted) + "\n")
            print(str(n) + "\t" + str(inserted) + "\n")


async def run(minimum, maximum):
    url = 'https:/xx.xxx.xxx/{}.json'
    tasks = []
    sem = asyncio.Semaphore(1000)   # Maximize the concurrent sessions to 1000, stay below the max open sockets allowed
    async with ClientSession() as session:
        for n in range(minimum, maximum):
            task = asyncio.ensure_future(create_task(sem, url.format(n), session))
            tasks.append(task)
        responses = asyncio.gather(*tasks)
        await responses


client = pymongo.MongoClient("mongodb://127.0.0.1:27017")
db = client["thread1"]
com = db["threadcol"]
start_time = time.time()
write_log = open("logging.log", "a")
min_item = 1
max_item = 100

loop = asyncio.get_event_loop()
future = asyncio.ensure_future(run(min_item, max_item))
loop.run_until_complete(future)
write_log.close()

1
অ্যাসিঙ্ক ব্যবহার করে মাল্টি থ্রেডিংয়ের চেয়ে দ্রুত কাজ করেছে।
টেক নাথ

সাহায্য করার জন্য ধন্যবাদ. আকর্ষণীয় ফলাফল।
ফরাসী

10

আপনি করতে পারেন যে বেশ কয়েকটি জিনিস আছে:

  1. পুনরায় সংযোগ করুন। নীচের মানদণ্ড অনুসারে এটি প্রায় 3 গুণ বেশি দ্রুত
  2. সমান্তরালভাবে আপনি একাধিক প্রক্রিয়াতে স্ক্র্যাপ করতে পারেন

এখান থেকে সমান্তরাল কোড

from threading import Thread
from Queue import Queue
q = Queue(concurrent * 2)
for i in range(concurrent):
    t = Thread(target=doWork)
    t.daemon = True
    t.start()
try:
    for url in open('urllist.txt'):
        q.put(url.strip())
    q.join()
except KeyboardInterrupt:
    sys.exit(1)

পুনরায় ব্যবহারযোগ্য সংযোগের জন্য এই প্রশ্ন থেকে সময়

>>> timeit.timeit('_ = requests.get("https://www.wikipedia.org")', 'import requests', number=100)
Starting new HTTPS connection (1): www.wikipedia.org
Starting new HTTPS connection (1): www.wikipedia.org
Starting new HTTPS connection (1): www.wikipedia.org
...
Starting new HTTPS connection (1): www.wikipedia.org
Starting new HTTPS connection (1): www.wikipedia.org
Starting new HTTPS connection (1): www.wikipedia.org
52.74904417991638
>>> timeit.timeit('_ = session.get("https://www.wikipedia.org")', 'import requests; session = requests.Session()', number=100)
Starting new HTTPS connection (1): www.wikipedia.org
15.770191192626953

6

আপনি দুটি দিক দিয়ে আপনার কোড উন্নত করতে পারেন:

  • একটি ব্যবহার করে Session, যাতে প্রতিটি অনুরোধে সংযোগটি পুনরায় সাজানো না হয় এবং খোলা রাখা হয়;

  • আপনার কোডটিতে সমান্তরালতা ব্যবহার করে asyncio;

এখানে একবার দেখুন https://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html


2
আপনি আরও কিছু বিবরণ যুক্ত করতে পারেন?
টেক নাথ

4

আপনি সম্ভবত যা খুঁজছেন তা হ'ল অ্যাসিনক্রোনাস স্ক্র্যাপিং। আমি আপনাকে কিছু ব্যাচ url তৈরি করার পরামর্শ দিচ্ছি, অর্থাৎ 5 টি ইউআরএল (ওয়েবসাইট ক্র্যাশ না করার চেষ্টা করুন), এবং এগুলিকে অবিচ্ছিন্নভাবে স্ক্র্যাপ করুন। আপনি যদি অ্যাসিঙ্ক সম্পর্কে বেশি কিছু জানেন না, তবে লিবারি অ্যাসিনসিওর জন্য গুগল। আশা করি আমি তোমাকে সাহায্য করতে পারব :)


1
আপনি আরও কিছু বিশদ যুক্ত করতে পারেন।
টেক নাথ

3

অনুরোধগুলি খণ্ডন করার চেষ্টা করুন এবং মঙ্গোডিবি বাল্ক রাইটিং ক্রিয়াকলাপটি ব্যবহার করুন।

  • অনুরোধগুলি গ্রুপ করুন (প্রতি গ্রুপে 100 টি অনুরোধ)
  • গ্রুপগুলির মাধ্যমে ইটারেট করুন
  • ডেটা আনার জন্য অ্যাসিক্রোনাস রিকোয়েস্ট মডেলটি ব্যবহার করুন (একটি গ্রুপের URL)
  • একটি গ্রুপ শেষ করার পরে ডিবি আপডেট করুন (বাল্ক রাইটিং অপারেশন)

এটি নিম্নলিখিত উপায়ে প্রচুর সময় সাশ্রয় করতে পারে * মঙ্গোডিবি লেটেন্সি লিখুন * সিঙ্ক্রোনাস নেটওয়ার্ক কল ল্যাটেন্সি

তবে সমান্তরাল অনুরোধের গণনা (ছান আকার) বৃদ্ধি করবেন না, এটি সার্ভারের নেটওয়ার্ক লোড বাড়িয়ে তুলবে এবং সার্ভার এটিকে ডিডিওএস আক্রমণ হিসাবে ভাবতে পারে।

  1. https://api.mongodb.com/python/current/examples/bulk.html

1
আপনি অনুরোধ এবং গ্রুপ গোষ্ঠীবদ্ধ আনা কোড ব্যাপারে সাহায্য করতে পারেন
টেক নাথ

3

ধরে নিই যে আপনি এপিআই দ্বারা অবরুদ্ধ হবেন না এবং কোনও হারের সীমা নেই, এই কোডটি প্রক্রিয়াটি 50 বার দ্রুত করা উচিত (আরও বেশি কারণ সমস্ত অনুরোধ এখন একই সেশনটি ব্যবহার করে প্রেরণ করা হয়েছে)।

import pymongo
import threading

client = pymongo.MongoClient("mongodb://127.0.0.1:27017")
db = client["thread1"]
com = db["threadcol"]
start_time = time.time()
logs=[]

number_of_json_objects=1417750
number_of_threads=50

session=requests.session()

def scrap_write_log(session,start,end):
    for n in range(start, end):
        response = session.get("https:/xx.xxx.xxx/{}.json".format(n))
        if response.status_code == 200:
            try:
                logs.append(str(n) + "\t" + str(com.insert_one(json.loads(response.text))) + "\n")
                print(str(n) + "\t" + str(inserted) + "\n")
            except:
                logs.append(str(n) + "\t" + "Failed to insert" + "\n")
                print(str(n) + "\t" + "Failed to insert" + "\n")

thread_ranges=[[x,x+number_of_json_objects//number_of_threads] for x in range(0,number_of_json_objects,number_of_json_objects//number_of_threads)]

threads=[threading.Thread(target=scrap_write_log, args=(session,start_and_end[0],start_and_end[1])) for start_and_end in thread_ranges]

for thread in threads:
    thread.start()
for thread in threads:
    thread.join()

with open("logging.log", "a") as f:
    for line in logs:
        f.write(line)

2

আমি অনেক বছর আগে একই প্রশ্ন ছিল। পাইথন-ভিত্তিক উত্তরগুলি নিয়ে আমি কখনই সন্তুষ্ট নই, যা বেশ ধীর বা খুব জটিল complicated আমি অন্যান্য পরিপক্ক সরঞ্জামগুলিতে স্যুইচ করার পরে, গতিটি দ্রুত এবং আমি কখনই ফিরে আসি না।

প্রক্রিয়াটি দ্রুততর করার জন্য সম্প্রতি আমি এই জাতীয় পদক্ষেপগুলি নীচের মত ব্যবহার করছি

  1. txt এ একগুচ্ছ url তৈরি করুন
  2. aria2c -x16 -d ~/Downloads -i /path/to/urls.txtএই ফাইলগুলি ডাউনলোড করতে ব্যবহার করুন
  3. স্থানীয়ভাবে বিশ্লেষণ করুন

এটি এখন পর্যন্ত আমি আসা সবচেয়ে দ্রুত প্রক্রিয়া।

ওয়েব পৃষ্ঠাগুলি স্ক্র্যাপ করার ক্ষেত্রে, আমি একবারে পৃষ্ঠা একবারে দেখার পরিবর্তে প্রয়োজনীয় * .html ডাউনলোডও করি, যা আসলে কোনও তাত্পর্য করে না। আপনি যখন পৃষ্ঠাতে যান মত পাইথন সরঞ্জামগুলির সাথে, আঘাত requestsবা scrapyবা urllibএখনও ক্যাশে, এটা এবং আপনার জন্য পুরো ওয়েব কন্টেন্ট ডাউনলোড করুন।


1

প্রথমে সমস্ত লিঙ্কের তালিকা তৈরি করুন কারণ সবগুলি একই হয় কেবল এটি পুনরাবৃত্তি করুন।

list_of_links=[]
for i in range(1,1417749):
    list_of_links.append("https:/xx.xxx.xxx/{}.json".format(str(i)))

t_no=2
for i in range(0, len(list_of_links), t_no):
    all_t = []
    twenty_links = list_of_links[i:i + t_no]
    for link in twenty_links:
        obj_new = Demo(link,)
        t = threading.Thread(target=obj_new.get_json)
        t.start()
        all_t.append(t)
    for t in all_t:
        t.join()

class Demo:
    def __init__(self, url):
        self.json_url = url

def get_json(self):
    try:
       your logic
    except Exception as e:
       print(e)

কেবলমাত্র__ বৃদ্ধি বা হ্রাস করে আপনি কোনও থ্রেড পরিবর্তন করতে পারবেন না ..

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.