Python + splinter + http: Ошибка – httplib.ResponseNotReady
С splinter и Python у меня есть два потока, каждый из которых посещает один и тот же основной URL-адрес, но разные маршруты, например, один поток: mainurl.com/threadone
и поток двух обращений: mainurl.com/threadtwo
:
from splinter import Browser browser = Browser('chrome')
Но натолкнулась на следующую ошибку:
Traceback (most recent call last): File "multi_thread_practice.py", line 299, in <module> main() File "multi_thread_practice.py", line 290, in main first_method(r) File "multi_thread_practice.py", line 195, in parser second_method(title, name) File "multi_thread_practice.py", line 208, in confirm_product third_method(current_url) File "multi_thread_practice.py", line 214, in buy_product browser.visit(url) File "/Users/joshua/anaconda/lib/python2.7/site-packages/splinter/driver/webdriver/__init__.py", line 184, in visit self.driver.get(url) File "/Users/joshua/anaconda/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 261, in get self.execute(Command.GET, {'url': url}) File "/Users/joshua/anaconda/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 247, in execute response = self.command_executor.execute(driver_command, params) File "/Users/joshua/anaconda/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 464, in execute return self._request(command_info[0], url, body=data) File "/Users/joshua/anaconda/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 488, in _request resp = self._conn.getresponse() File "/Users/joshua/anaconda/lib/python2.7/httplib.py", line 1108, in getresponse raise ResponseNotReady() httplib.ResponseNotReady
Какая ошибка и как я должен обращаться с проблемой?
Заранее благодарю вас и обязательно отвечу / примите ответ
КОД ДОБАВЛЕН
import time from splinter import Browser import threading browser = Browser('chrome') start_time = time.time() urlOne = 'http://www.practiceurl.com/one' urlTwo = 'http://www.practiceurl.com/two' baseUrl = 'http://practiceurl.com' browser.visit(baseUrl) def secondThread(url): print 'STARTING 2ND REQUEST: ' + str(time.time() - start_time) browser.visit(url) print 'END 2ND REQUEST: ' + str(time.time() - start_time) def mainThread(url): print 'STARTING 1ST REQUEST: ' + str(time.time() - start_time) browser.visit(url) print 'END 1ST REQUEST: ' + str(time.time() - start_time) def main(): threadObj = threading.Thread(target=secondThread, args=[urlTwo]) threadObj.daemon = True threadObj.start() mainThread(urlOne) main()
- Существуют ли ограничения использования библиотеки Threading для небольших задач async в среде Django?
- Исключение в потоке: должна быть последовательность, а не экземпляр
- Потоки Python. Как заблокировать поток?
- Python: Огромное чтение файла с помощью linecache. Доступ к обычным файлам открыт ()
- Как запустить несколько заданий в одном Sparkcontext из отдельных потоков в PySpark?
Насколько я могу судить, то, что вы пытаетесь сделать, невозможно в одном браузере. Splinter действует на фактический браузер, и, таким образом, передача многих команд одновременно вызывает проблемы. Он действует так же, как человек будет взаимодействовать с браузером (автоматически, конечно). Можно открыть много окон браузера, но вы не можете отправлять запросы в другом потоке, не получая ответа от предыдущего запроса. Это вызывает ошибку CannotSendRequest. Итак, я рекомендую (если вам нужно использовать потоки) открыть два браузера, а затем использовать потоки для отправки запроса через каждый из них. В противном случае это невозможно.
Этот поток находится на селене, но информация передается. Селен несколько вкладок одновременно. Это говорит о том, что вы хотите (я полагаю) сделать это невозможно. И зеленая галочка отвечает тем же рекомендациям, что и я.
Надеюсь, что это не слишком сильно отвлекает вас и помогает вам.
EDIT: просто чтобы показать:
import time from splinter import Browser import threading browser = Browser('firefox') browser2 = Browser('firefox') start_time = time.time() urlOne = 'http://www.practiceurl.com/one' urlTwo = 'http://www.practiceurl.com/two' baseUrl = 'http://practiceurl.com' browser.visit(baseUrl) def secondThread(url): print 'STARTING 2ND REQUEST: ' + str(time.time() - start_time) browser2.visit(url) print 'END 2ND REQUEST: ' + str(time.time() - start_time) def mainThread(url): print 'STARTING 1ST REQUEST: ' + str(time.time() - start_time) browser.visit(url) print 'END 1ST REQUEST: ' + str(time.time() - start_time) def main(): threadObj = threading.Thread(target=secondThread, args=[urlTwo]) threadObj.daemon = True threadObj.start() mainThread(urlOne) main()
Обратите внимание, что я использовал firefox, потому что у меня нет установленного хромированного ребра.
Возможно, неплохо было бы подождать, пока браузеры откроются, чтобы убедиться, что они полностью готовы, прежде чем начнутся таймеры.
@GenericSnake верна в этом вопросе. Чтобы добавить немного к этому, я настоятельно рекомендую вам реорганизовать ваш код для использования библиотеки многопроцессорности , главным образом потому, что реализация потоковой передачи использует GIL :
В CPython из-за блокировки Global Interpreter Lock только один поток может выполнять код Python сразу (хотя определенные библиотеки, ориентированные на производительность, могут преодолеть это ограничение). Если вы хотите, чтобы ваше приложение лучше использовало вычислительные ресурсы многоядерных машин, вам рекомендуется использовать многопроцессорную обработку. Тем не менее, потоки по-прежнему являются подходящей моделью, если вы хотите одновременно запускать несколько задач, связанных с вводом-выводом.
На самом деле хорошая вещь, использующая многопроцессорность, заключается в том, что вы можете реорганизовать свой код, чтобы избежать дублирования метода secondThread
и mainThread
, например, таким образом (последнее, не забудьте очистить ресурсы, которые вы используете, например browser.quit()
до закройте браузер, как только вы закончите):
import time from splinter import Browser from multiprocessing import Process import os os.environ['PATH'] = os.environ[ 'PATH'] + "path/to/geckodriver" + "path/to/firefox/binary" start_time = time.time() urlOne = 'http://pythoncarsecurity.com/Support/FAQ.aspx' urlTwo = 'http://pythoncarsecurity.com/Products/' def url_visitor(url): print("url called: " + url) browser = Browser('firefox') print('STARTING REQUEST TO: ' + url + " at "+ str(time.time() - start_time)) browser.visit(url) print('END REQUEST TO: ' + url + " at "+ str(time.time() - start_time)) def main(): p1 = Process(target=url_visitor, args=[urlTwo]) p2 = Process(target=url_visitor, args=[urlOne]) p1.start() p2.start() p1.join() #join processes to the main process to see the output p2.join() if __name__=="__main__": main()
Это дает нам следующий результат (время будет зависеть от вашей системы):
url called: http://pythoncarsecurity.com/Support/FAQ.aspx url called: http://pythoncarsecurity.com/Products/ STARTING REQUEST TO: http://pythoncarsecurity.com/Support/FAQ.aspx at 10.763000011444092 STARTING REQUEST TO: http://pythoncarsecurity.com/Products/ at 11.764999866485596 END REQUEST TO: http://pythoncarsecurity.com/Support/FAQ.aspx at 16.20199990272522 END REQUEST TO: http://pythoncarsecurity.com/Products/ at 16.625999927520752
Редактирование : проблема с многопоточным потоком и Selenium заключается в том, что экземпляр браузера не является потокобезопасным, единственный способ, которым я нашел обход этой проблемы, – это получить блокировку на url_visitor
, однако в этом случае вы теряете преимущество многопоточности , Вот почему я считаю, что использование нескольких браузеров намного выгоднее (хотя, я думаю, у вас есть некоторые очень специфические требования), см. Код ниже:
import time from splinter import Browser import threading from threading import Lock import os os.environ['PATH'] = os.environ[ 'PATH'] + "/path/to/chromedriver" start_time = time.time() urlOne = 'http://pythoncarsecurity.com/Support/FAQ.aspx' urlTwo = 'http://pythoncarsecurity.com/Products/' browser = Browser('chrome') lock = threading.Lock()#create a lock for the url_visitor method def init(): browser.visit("https://www.google.fr") driver = browser.driver driver.execute_script("window.open('{0}', '_blank');") #create a new tab tabs = driver.window_handles def url_visitor(url, tabs): with lock: if tabs != 0: browser.driver.switch_to_window(browser.driver.window_handles[tabs]) print("url called: " + url) print('STARTING REQUEST TO: ' + url + " at "+ str(time.time() - start_time)) browser.visit(url) print('END REQUEST TO: ' + url + " at "+ str(time.time() - start_time)) browser.quit() def main(): p1 = threading.Thread(target=url_visitor, args=[urlTwo, 0]) p2 = threading.Thread(target=url_visitor, args=[urlOne, 1]) p1.start() p2.start() if __name__=="__main__": init() #create a browser with two tabs main()
- Многие символы emoji не читаются при чтении файла python
- Сгруппированные данные гистограммы на основе Python
- Как получить доступ к данным из потока python
- Python .NET, многопоточность и цикл событий Windows
- Python, Ruby, Haskell – Они обеспечивают истинную многопоточность?
- Многопоточность / многопоточность Python используется для одновременной операции копирования файлов
- Руководство по использованию Concurrent.futures – простой пример использования потоков и обработки
- wxPython, захват вывода из подпроцесса в режиме реального времени
- Как разрешить индексы TypeError: list должны быть целыми, а не str после добавления очереди в поточную функцию
- Блокировка объекта Django
- Python Многопоточный цикл for с ограниченными потоками