• B правой части каждого сообщения есть стрелки и . Не стесняйтесь оценивать ответы. Чтобы автору вопроса закрыть свой тикет, надо выбрать лучший ответ. Просто нажмите значок в правой части сообщения.

Парсер на Python

Rubrika

Member
10.11.2017
14
0
BIT
0
Всем доброго времени суток, есть файл в 5кк ссылок, нужно получить ip каждого url , делал это через сокеты (gethostbyname) и пулом процессов , на скорости в 60 потоков обрабатывает где-то 50-70к строк в час, хотя должен в несколько раз больше, проблема оказалась в таймауте, т.е. если ссылка невалидна, то ожидание ответа очень долгое, а стандартного таймаута для этого метода не предусмотрено.
Гуглил, гуглил, еще раз гуглил, читал библиотеки и наткнулся на gevent и почти готовое решение моей задачи
Python:
>>> import gevent
>>> from gevent import socket
>>> urls = ['www.google.com', 'www.example.com', 'www.python.org']
>>> jobs = [gevent.spawn(socket.gethostbyname, url) for url in urls]
>>> gevent.joinall(jobs, timeout=2)
>>> [job.value for job in jobs]
['74.125.79.106', '208.77.188.166', '82.94.164.162']

Может от того, что устал или просто от банальной нехватки опыта работы с питоном, но собственно вопрос - как ограничить создание гринлетов? Просто обычный цикл для построчной работы будет читать строку, спавнить гринлет, получать ip и так для каждой строки в файле, но, повторюсь, в файле 5кк строк, памяти не хватит, а хотелось бы , чтобы определенное количество гринлетов создавалось, получало ip и переходило к следующей строке, как?
 

f22

Codeby Academy
Gold Team
05.05.2019
1 922
226
BIT
1 668
Всем доброго времени суток, есть файл в 5кк ссылок, нужно получить ip каждого url
Если задача именно в этом, то проще всего использовать уже написанные приложения, например
dig {ip}
host {ip}
nslookup {ip}

Любое из них можно запустить в цикле, добавив ввод из файла
Например
while read line; do dig ${line} | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}" | sort -u | tail -1 >> output.txt; done < url.q
В файле url.q должен быть список ip, вывод будет в файл output.txt
 

Rubrika

Member
10.11.2017
14
0
BIT
0
Если задача именно в этом, то проще всего использовать уже написанные приложения, например
dig {ip}
host {ip}
nslookup {ip}

Любое из них можно запустить в цикле, добавив ввод из файла
Например
while read line; do dig ${line} | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}" | sort -u | tail -1 >> output.txt; done < url.q
В файле url.q должен быть список ip, вывод будет в файл output.txt
Спасибо за варианты решения, но задача не в том, как получить ip, а как это сделать многопоточно и ограничить время на само получение (запрос)

может у кого есть еще какие-либо идеи?
 
Последнее редактирование:

s13nh

Member
22.03.2020
10
0
BIT
0
Из описания gevent.joinall(jobs, timeout)
timeout
( ) – If given, the maximum number of seconds to wait.
Т.е. передав в gevent.joinall 10000 url, и timeout=2 выполнение закончится через 2 секунды, не зависимо успеют отработать все jobs или нет.

Вот пример через гринлет пул(не увере, что быстрее):
Python:
#!/usr/bin/python

from __future__ import print_function
import gevent
import time
from gevent import socket
from gevent.pool import Pool

N = 1000
pool = Pool(60)
finished = 0

def job(url):
    global finished
    try:
        try:
            ip = socket.gethostbyname(url)
            print('%s = %s' % (url, ip))
        except socket.gaierror as ex:
            print('%s failed with %s' % (url, ex))
    finally:
        finished += 1

start_time = time.time()
for x in range(1, N):
    pool.spawn(job, '%s.com' % x)
pool.join()

print('finished within: %s/%s' % (finished, N))
print("--- %s seconds ---" % (time.time() - start_time))
 

Rubrika

Member
10.11.2017
14
0
BIT
0
Из описания gevent.joinall(jobs, timeout)
timeout
( ) – If given, the maximum number of seconds to wait.
Т.е. передав в gevent.joinall 10000 url, и timeout=2 выполнение закончится через 2 секунды, не зависимо успеют отработать все jobs или нет.

Вот пример через гринлет пул(не увере, что быстрее):
Python:
#!/usr/bin/python

from __future__ import print_function
import gevent
import time
from gevent import socket
from gevent.pool import Pool

N = 1000
pool = Pool(60)
finished = 0

def job(url):
    global finished
    try:
        try:
            ip = socket.gethostbyname(url)
            print('%s = %s' % (url, ip))
        except socket.gaierror as ex:
            print('%s failed with %s' % (url, ex))
    finally:
        finished += 1

start_time = time.time()
for x in range(1, N):
    pool.spawn(job, '%s.com' % x)
pool.join()

print('finished within: %s/%s' % (finished, N))
print("--- %s seconds ---" % (time.time() - start_time))
Немного не понял вашу реализацию,
1) Все идет в однопоточном режиме
2) Задержка на отклик 10 сек, хотя я изначально и говорил, что проблема именно в этом )
 

s13nh

Member
22.03.2020
10
0
BIT
0
Попробуй вот этот принцип, для простоты я просто генерирую url:
Python:
# pool.py
#!/usr/bin/python

from __future__ import print_function
import gevent
import time
from gevent import socket
from gevent.pool import Pool
import sys
from gevent import config

config.resolver = 'ares'

N = sys.argv[1]
pool = Pool(200)

finished = 0
available = []

def job(url):
    global finished
    global available
    try:
        try:
            ip = socket.gethostbyname(url)
            available.append(ip)
            print('%s = %s' % (url, ip))
        except socket.gaierror as ex:
            print('%s failed with %s' % (url, ex))
    finally:
        finished += 1
    return finished

def do_with_timeout(timeout, url):
    try:
        gevent.with_timeout(timeout, job, url)
    except:
        pass

timeout = 10
start_time = time.time()
for x in range(int(N)):
    pool.spawn(do_with_timeout, timeout, '%s.com' % x)
pool.join()

#print(available)
print('finished within: %s/%s' % (finished, N))
print('available: %s/%s' % (len(available), N))
print("--- %s seconds ---" % (time.time() - start_time))

Запускать python pool.py N
где N - количество генерируемых url

у меня при запуске python pool.py 60000
finished within: 60000/60000
available: 46985/60000
--- 356.2432940006 seconds ---
Но нужно помнить что мы прерываем выполнение gethostbyname по timeout, и чем он меньше, тем больше вероятность, что ответ просто не успел прийти
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!