Multithreading selenium线程对Python的刮削安全吗?
我正在执行一个带线程的Python脚本,其中给定了一个我放入队列中的“查询”术语,我使用查询参数创建url,设置cookies并解析网页以返回产品和这些产品的url。这是剧本 任务:对于给定的一组查询,将前20个产品ID存储在一个文件中,如果查询返回的结果较少,则将其存储在较低的文件中 我记得读到硒不是线程安全的。只是想确保这个问题是因为这个限制而发生的,有没有办法让它在并发线程中工作?主要的问题是,该脚本是I/O绑定的,因此在抓取大约3000个url抓取时非常慢Multithreading selenium线程对Python的刮削安全吗?,multithreading,python-2.7,selenium,cookies,thread-safety,Multithreading,Python 2.7,Selenium,Cookies,Thread Safety,我正在执行一个带线程的Python脚本,其中给定了一个我放入队列中的“查询”术语,我使用查询参数创建url,设置cookies并解析网页以返回产品和这些产品的url。这是剧本 任务:对于给定的一组查询,将前20个产品ID存储在一个文件中,如果查询返回的结果较少,则将其存储在较低的文件中 我记得读到硒不是线程安全的。只是想确保这个问题是因为这个限制而发生的,有没有办法让它在并发线程中工作?主要的问题是,该脚本是I/O绑定的,因此在抓取大约3000个url抓取时非常慢 from pyvirtuald
from pyvirtualdisplay import Display
from data_mining.scraping import scraping_conf as sf #custom file with rules for scraping
import Queue
import threading
import urllib2
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
num_threads=5
COOKIES=sf.__MERCHANT_PARAMS[merchant_domain]['COOKIES']
query_args =sf.__MERCHANT_PARAMS[merchant_domain]['QUERY_ARGS']
class ThreadUrl(threading.Thread):
"""Threaded Url Grab"""
def __init__(self, queue, out_queue):
threading.Thread.__init__(self)
self.queue = queue
self.out_queue = out_queue
def url_from_query(self,query):
for key,val in query_args.items():
if query_args[key]=='query' :
query_args[key]=query
print "query", query
try :
url = base_url+urllib.urlencode(query_args)
print "url"
return url
except Exception as e:
log()
return None
def init_driver_and_scrape(self,base_url,query,url):
# Will use Pyvirtual display later
#display = Display(visible=0, size=(1024, 768))
#display.start()
fp = webdriver.FirefoxProfile()
fp.set_preference("browser.download.folderList",2)
fp.set_preference("javascript.enabled", True)
driver = webdriver.Firefox(firefox_profile=fp)
driver.delete_all_cookies()
driver.get(base_url)
for key,val in COOKIES[exp].items():
driver.add_cookie({'name':key,'value':val,'path':'/','domain': merchant_domain,'secure':False,'expiry':None})
print "printing cookie name & value"
for cookie in driver.get_cookies():
if cookie['name'] in COOKIES[exp].keys():
print cookie['name'],"-->", cookie['value']
driver.get(base_url+'search=junk') # To counter any refresh issues
driver.implicitly_wait(20)
driver.execute_script("window.scrollTo(0, 2000)")
print "url inside scrape", url
if url is not None :
flag = True
i=-1
row_data,row_res=(),()
while flag :
i=i+1
try :
driver.get(url)
key=sf.__MERCHANT_PARAMS[merchant_domain]['GET_ITEM_BY_ID']+str(i)
print key
item=driver.find_element_by_id(key)
href=item.get_attribute("href")
prod_id=eval(sf.__MERCHANT_PARAMS[merchant_domain]['PRODUCTID_EVAL_FUNC'])
row_res=row_res+(prod_id,)
print url,row_res
except Exception as e:
log()
flag =False
driver.delete_all_cookies()
driver.close()
return query+"|"+str(row_res)+"\n" # row_data, row_res
else :
return [query+"|"+"None"]+"\n"
def run(self):
while True:
#grabs host from queue
query = self.queue.get()
url=self.url_from_query(query)
print "query, url", query, url
data=self.init_driver_and_scrape(base_url,query,url)
self.out_queue.put(data)
#signals to queue job is done
self.queue.task_done()
class DatamineThread(threading.Thread):
"""Threaded Url Grab"""
def __init__(self, out_queue):
threading.Thread.__init__(self)
self.out_queue = out_queue
def run(self):
while True:
#grabs host from queue
data = self.out_queue.get()
fh.write(str(data)+"\n")
#signals to queue job is done
self.out_queue.task_done()
start = time.time()
def log():
logging_hndl=logging.getLogger("get_results_url")
logging_hndl.exception("Stacktrace from "+"get_results_url")
df=pd.read_csv(fh_query, sep='|',skiprows=0,header=0,usecols=None,error_bad_lines=False) # read all queries
query_list=list(df['query'].values)[0:3]
def main():
exp="Control"
#spawn a pool of threads, and pass them queue instance
for i in range(num_threads):
t = ThreadUrl(queue, out_queue)
t.setDaemon(True)
t.start()
#populate queue with data
print query_list
for query in query_list:
queue.put(query)
for i in range(num_threads):
dt = DatamineThread(out_queue)
dt.setDaemon(True)
dt.start()
#wait on the queue until everything has been processed
queue.join()
out_queue.join()
main()
print "Elapsed Time: %s" % (time.time() - start)
虽然我应该从每个url页面获取所有搜索结果,但我只获取第一个,I=0搜索卡,并且这不会对所有查询/url执行。我做错了什么
我的期望-
url inside scrape http://<masked>/search=nike+costume
searchResultsItem0
url inside scrape http://<masked>/search=red+tops
searchResultsItem0
url inside scrape http://<masked>/search=halloween+costumes
searchResultsItem0
and more searchResultsItem(s) , like searchResultsItem1,searchResultsItem2 and so on..
url内刮http:///search=nike+服装
searchResultsItem0
刮内urlhttp:///search=red+顶
searchResultsItem0
刮内urlhttp:///search=halloween+服装
searchResultsItem0
以及更多searchResultsItem,如searchResultsItem1、searchResultsItem2等。。
我得到的
url inside scrape http://<masked>/search=nike+costume
searchResultsItem0
url inside scrape http://<masked>/search=nike+costume
searchResultsItem0
url inside scrape http://<masked>/search=nike+costume
searchResultsItem0
url内刮http:///search=nike+服装
searchResultsItem0
刮内urlhttp:///search=nike+服装
searchResultsItem0
刮内urlhttp:///search=nike+服装
searchResultsItem0
基本代码取自
另外,当我使用Pyvirtual display时,它是否也适用于线程?我还使用了具有相同Selenium代码的进程,它给出了相同的错误基本上它打开了3个Firefox浏览器,具有精确的URL,同时它应该从队列中的不同项目打开它们。在这里,我将规则存储在将作为sf导入的文件中,该文件具有基本域的所有自定义属性
因为设置cookies是我脚本中不可或缺的一部分,所以我不能使用Drysrap
编辑:
我试图定位错误,下面是我发现的-
在自定义规则文件中,我将上面的“sf”称为QUERY_ARGS
__MERCHANT_PARAMS = {
"some_domain.com" :
{
COOKIES: { <a dict of dict, masked here>
},
... more such rules
QUERY_ARGS:{'search':'query'}
}
\u商户参数={
“some_domain.com”:
{
曲奇:{
},
……更多这样的规则
查询参数:{'search':'QUERY'}
}
所以真正发生的是,一打电话
query\u args=sf.\uu MERCHANT\u参数[MERCHANT\u domain]['query\u args']
-这应该返回dict
{'search':'query'}
,当它返回时
AttributeError:“模块”对象没有属性
“\u ThreadUrl\u MERCHANT\u PARAMS”
这就是我不理解线程如何传递“\u ThreadUrl\uuuu”的地方。我还尝试在url\u from\u查询方法中重新初始化查询参数,但这不起作用
任何关于我做错了什么的提示?我可能很晚才回答这个问题。但是,我测试了它的python2.7,多线程和多进程两个选项都可以与selenium一起使用,并且它正在打开两个独立的浏览器