【前言】
# 本腳本用來爬取jd的頁面:http://list.jd.com/list.html?cat=737,794,870到 # ......http://list.jd.com/list.html?cat=737,794,870&page=11&JL=6_0_0的所有html的內容和圖片。 # 本腳本僅用於技術交流,請勿用於其他用途 # by River # qq : 179621252 # Date : 2014-12-02 19:00:00
【需求說明】
以京東爲示例,爬取頁面的,獲取頁面中得數據:記錄到data.txt;獲取頁面中得圖片,保存下來。
1、list的url如下
2、商品詳情頁的url如下:
【技術說明】
使用了python的以下庫 import os#檢查文件是否存在等 from HTMLParser import HTMLParser#用於解析html的庫,有坑:如果2.6的python,可能悲劇 import httplib,re#發起http請求 import sys,json,datetime,bisect#使用了二分快速查找 from urlparse import urlparse#解析url,分析出url的各部分功能 from threading import Thread#使用多線程 import socket #設置httplib超時時間
【代碼邏輯說明】
1、run(獲取最終要的結果)
2、parseListpageurl:返回list的總共的頁面數量
3、judgelist:判斷該list是否已經爬取完畢了,第一個list中的所有url、最後list的所有url都爬取完畢了,那麼久說明list的所有page爬取完畢了(實際上是一種弱校驗)
4、getfinalurl_content:如果list沒爬取完畢,每個list爬取,解析list中得每個html(判斷html是否爬取過),獲得內容和img
【坑說明】
1、需要設置超時時間,和重試,否則爬取一個url卡住的時候,整個線程都悲劇了。
2、有編碼的坑,如果頁面是gb2312的編碼,需要轉換爲utf-8的編碼:httprestmp.decode('gbk').encode('utf-8')
3、parser.feed的內容,如果存在一些特殊字符,可能需要替換,否則解析出來會莫名不對
4、圖片保存,根據url獲取前面兩個數字,保存。以免一個目錄下保存了過多的圖片。
【執行結果】
1、console輸出
2、data.txt存儲解析出來的內容
3、judegurl.txt(保存已經爬取過的url)
4、圖片(下載的圖片)
【代碼詳情】
# -*- coding: utf-8 -*- __author__ = 'River' # 本腳本用來爬取jd的頁面:http://list.jd.com/list.html?cat=737,794,870到 # ......http://list.jd.com/list.html?cat=737,794,870&page=11&JL=6_0_0的所有html的內容和圖片。 # 本腳本僅用於技術交流,請勿用於其他用途 # by River # qq : 179621252 # Date : 2014-12-02 19:00:00 import os#創建文件 from HTMLParser import HTMLParser#用於解析html的庫,有坑:如果2.6的python,可能悲劇 import httplib,re#發起http請求 import sys,json,datetime,bisect#使用了二分快速查找 from urlparse import urlparse#解析url,分析出url的各部分功能 from threading import Thread#使用多線程 import socket #設置httplib超時時間 #定義一個ListPageParser,用於解析ListPage,如http://list.jd.com/list.html?cat=737,794,870 #htmlparser的使用簡介 #定義intt方法:需要使用到得屬性 #定義handle_starttag,處理你想分析的tag的具體操作 #定義handle_data,遇到你定義的情況,獲取相應標籤的data #定義你獲取最終返回的各種數據 class ListPageParser(HTMLParser): def __init__(self): self.handledtags=['a'] self.processing=None self.flag='' self.link='' self.setlinks=set()##該list頁面中包含的每個商品的url,定義爲set,主要是爲了使用其特性:去重 self.pageNo=1 self.alldata=[] self.lasturl=""#指的最後一頁的url如<a href="http://list.jd.com/list.html?cat=737%2C794%2C798&page=10&JL=6_0_0">10</a> HTMLParser.__init__(self) def handle_starttag(self, tag, attrs): pattern = re.compile(r'^[0-9]{2,}') pattern2=re.compile(r'^http:\/\/item.jd.com\/\d{1,10}.html$')#取出link pattern3=re.compile(r'^http:\/\/list.jd.com\/list.html\?cat=\d{0,9}%2C\d{0,9}%2C\d{0,9}&page=*')#取出link #attrs是屬性的list,每個屬性(包含key,value)又是一個元組 #<a target="_blank" href="http://item.jd.com/1258277.html" onclick="log("search","list",window.location.href,798,5,1258277,2,1,1,2,A)">創維酷開(coocaa) K50J 50英寸八核智能wifi網絡安卓平板液晶電視(黑色)<font style="color: #ff0000;" name="1258277" class="adwords"></font></a> #已上爲例子:判斷了該list的長度爲3(其他的a標籤就被過濾了) if tag in self.handledtags and len(attrs)==3 :#非常關鍵的是,找出你想的url和不想要的url的區別 #print "debug:attrs",attrs self.flag='' self.data='' self.processing=tag for target,href in attrs:#非常關鍵的是,找出你想的url和不想要的url的區別 if pattern2.match(href):#再加一層判斷,如果匹配上pattern2,說明是我們想要的url self.setlinks.add(href) else: pass #怎樣獲取list中最後一頁的url?分析吧:<a href="http://list.jd.com/list.html?cat=737%2C794%2C798&page=10&JL=6_0_0">10</a> #1、長度爲1 #2,href是由規則的:cat=737%2C794%2C798&page=10&JL=6_0_0,所以,以下代碼就出來了 if tag in self.handledtags and len(attrs)==1 : self.flag='' self.data='' self.processing=tag for href,url in attrs:#非常關鍵的是,找出你想的url和不想要的url的區別 #print 'debug:attrs',attrs if pattern3.match(url): #print 'debug:url',url self.lasturl=url else: pass def handle_data(self, data): if self.processing:#去掉空格 pass#其實這裏我們根本沒使用獲取到得data,就pass把 else: pass def handle_endtag(self, tag): if tag==self.processing: self.processing=None def getlinks(self): return self.setlinks def getlasturl(self): return self.lasturl #定義一個FinallPageParser,用於解析最終的html頁面,如http://item.jd.com/1258277.html #FinallPageParser的定義過程參考上個parser,關鍵是怎樣分析頁面,最終寫出代碼,並且驗證,這裏就不詳細說了 class FinallPageParser(HTMLParser): def __init__(self): self.handledtags=['div','h1','strong','a','del','div','img','li','span','tbody','tr','th','td','i'] self.processing=None self.title='' self.jdprice='' self.refprice='' self.partimgs_show=set()#展示圖片 self.partimgs=set()#詳情圖片 self.partdetail={}#商品詳情,參數等 self.specification=[]#規格參數 self.typeOrsize=set()#尺碼和類型 self.div='' self.flag={} self.flag['refprice']='' self.flag['title']='' self.flag['jdprice']='' self.flag['typeOrsize']='' self.flag['partimgs']='' self.flag['partdetail']='' self.flag['specification']='' self.flag['typeOrsize']='' self.link='' self.partslinks={} HTMLParser.__init__(self) def handle_starttag(self, tag, attrs): self.titleflag='' self.flag['refprice']='' self.flag['title']='' self.flag['jdprice']='' self.flag['typeOrsize']='' self.flag['partimgs']='' self.flag['partdetail']='' self.flag['specification']='' self.flag['typeOrsize']='' if tag in self.handledtags: self.data='' self.processing=tag if tag=='div': for key,value in attrs: self.div=value# 取出div的name,判斷是否是所需要的圖片等元素 if tag=='i': self.flag['typeOrsize']='match' if tag=='a' and len(attrs)==2: tmpflag="" for key,value in attrs: if key=='href' and re.search(r'^http:\/\/item.jd.com\/[0-9]{1,10}.html$',value): tmpflag="first" if key=='title' and value!="": tmpflag=tmpflag+"second" if tmpflag== "firstsecond": self.flag['typeOrsize']='match' if tag=='h1': self.flag['title']='match' if tag=='strong' and len(attrs)==2: for tmpclass,id in attrs: if id=='jd-price': self.flag['jdprice']='match' if tag=='del': self.flag['refprice']='match' if tag=='li': self.flag['partdetail']='match' if tag=='th' or tag=='tr' or tag=='td' :#++++++++############################################879498.html td中有br的只取到第一個,需要把<br/>喜歡爲“” self.flag['specification']='match' if tag=='img' : imgtmp_flag='' imgtmp='' for key,value in attrs: if re.search(r'^http://img.*jpg|^http://img.*gif|^http://img.*png',str(value)) and (key=='src' or key=='data-lazyload'): imgtmp=value if key== 'width':############可能還有logo if re.search(r'^\d{1,9}$',value): if int(value)<=160: imgtmp_flag='no' break if self.div=="spec-items" and imgtmp!='': imgtmp=re.compile("/n5/").sub("/n1/",imgtmp) self.partimgs_show.add(imgtmp) elif imgtmp_flag!='no' and imgtmp!='': self.partimgs.add(imgtmp)# def handle_data(self, data): if self.processing: self.data+=data if self.flag['title']=='match':#獲取成功 self.title=data if self.flag['jdprice']=='match': self.jdprice=data.strip() if self.flag['typeOrsize']=='match': self.typeOrsize.add(data.strip()) if self.flag['refprice']=='match': self.refprice=data.strip() if self.flag['partdetail']=='match' and re.search(r':',data):#獲取成功 keytmp=data.split(":")[0].strip() valuetmp=data.split(":")[1].strip() self.partdetail[keytmp]=valuetmp if self.flag['specification']=='match' and data.strip() != '' and data.strip()!='主體': self.specification.append(data.strip()) else: pass def handle_endtag(self, tag): if tag==self.processing: self.processing=None def getdata(self): return {'title':self.title,'partimgs_show':self.partimgs_show,'jdprice':self.jdprice,'refprice':self.refprice,'partimgs':self.partimgs,'partdetail':self.partdetail,'specification':self.specification,'typeOrsize':self.typeOrsize} #定義方法httpread,用於發起http的get請求,返回http的獲取內容 #這也是代碼抽象的結果,如若不抽象這塊代碼出來,後續你回發現很多重複的寫這塊代碼 def httpread(host,url,headers): httprestmp='' try: conn = httplib.HTTPConnection(host) conn.request('GET',url,None,headers) httpres = conn.getresponse() httprestmp=httpres.read() except Exception,e: conn = httplib.HTTPConnection(host) conn.request('GET',url,None,headers) httpres = conn.getresponse() httprestmp=httpres.read() print e finally: if conn: conn.close() return httprestmp #定義方法sendhttp,調用httpread,獲取結果並替換編碼(gbk換爲utf-8),並保存到文件中(以免下次再去下載頁面,這樣就節省了時間) # def sendhttp(url,host,savefile): #定義http頭部,很多網站對於你不攜帶User-Agent及Referer等情況,是不允許你爬取。 #具體的http的頭部有些啥信息,你可以看chrome,右鍵審查元素,點擊network,點擊其中一個鏈接,查看request header headers = {"Host":host, "Origin":"http://www.jd.com/", "Referer":"http://www.jd.com/", "Content-type": "application/x-www-form-urlencoded; charset=UTF-8", "Accept": "text/html;q=0.9,image/webp,*/*;q=0.8", "User-Agent":"Mozilla/3.0 AppleWebKit/537.36 (KHTML,Gecko) Chrome/3.0.w4.", "Cookie":"__utmz=qwer2434.1403499.1.1.utmcsr=www.jd.com|utmccn=(refrral)|utmcmd=rferral|utmcct=/order/getnfo.action; _pst=xx89; pin=x9; unick=jaa; cshi3.com=D6045EA24A6FB9; _tp=sdyuew8r9e7r9oxr3245%3D%3D; user-key=1754; cn=0; ipLocation=%u7F0C; ipLoc97; areaId=1; mt_ext2%3a%27d; aview=6770.106|68|5479.665|675.735|6767.100|6757.13730|6ee.9ty711|1649.10440; atw=65.15.325.24353.-4|188.3424.-10|22; __j34|72.2234; __jdc=2343423; __jdve|-; __jdu=3434" } httprestmp='' try: httprestmp=httpread(host,url,headers) if httprestmp=='':# httprestmp=httpread(host,url,headers) if httprestmp=='':#重試2次 httprestmp=httpread(host,url,headers) except Exception,e: try: httprestmp=httpread(host,url,headers) if httprestmp=='':# httprestmp=httpread(host,url,headers) if httprestmp=='':#重試2次 httprestmp=httpread(host,url,headers) except Exception,e: print e print e if re.search(r'charset=gb2312',httprestmp):#如果是gb2312得編碼,就要轉碼爲utf-8(因爲全局都使用了utf-8) httprestmp.replace("charset=gb2312",'charset=utf-8') try: httprestmp=httprestmp.decode('gbk').encode('utf-8')#有可能轉碼失敗,所以要加上try except Exception,e:#如果html編碼本來就是utf8或者轉換編碼出錯的時候,就啥都不做,就用原始內容 print e try: with open(savefile, 'w') as file_object: file_object.write(httprestmp) file_object.flush() except Exception,e: print e return httprestmp #list的頁面的解析方法 def parseListpageurl(listpageurl): urlobj=urlparse(listpageurl) if urlobj.query: geturl=urlobj.path+"?"+urlobj.query else: geturl=urlobj.path htmlfile="html/list"+geturl if not os.path.exists(htmlfile): httpresult=sendhttp(geturl,urlobj.hostname,htmlfile) with open(htmlfile) as file: htmlcontent=file.read() parser= ListPageParser()#聲明一個解析對象 #http://list.jd.com/list.html?cat=737%2C794%2C870&page=11&JL=6_0_0,所以這裏需要把'amp;'去掉 parser.feed(htmlcontent.replace('amp;',''))#將html的內容feed進去 #print 'debug:htmlcontent',htmlcontent finalparseurl=parser.getlinks()#然後get數據即可 lastpageurl=parser.getlasturl() urlobj_lastpageurl=urlparse(lastpageurl) #print 'debug:urlobj_lastpageurl',urlobj_lastpageurl totalPageNo='0' #print urlobj if re.search(r'&',urlobj_lastpageurl.query): try: totalPageNo=urlobj_lastpageurl.query.split("&")[1].split("=")[1]#獲得總共有多少頁 except Exception,e: print "lastpageurl:"+str(lastpageurl) print e parseListpageurl_rult={'finalparseurls':finalparseurl,'totalPageNo':totalPageNo} if parseListpageurl_rult['finalparseurls'] !="" and parseListpageurl_rult['totalPageNo']!='': print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",parse listpageurl succ:"+listpageurl else: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",parse listpageurl fail:"+listpageurl return parseListpageurl_rult #最終的html頁面的解析方法:會使用到html得解析器FinallPageParser def parseFinallyurl(finallyurl): urlobj=urlparse(finallyurl) geturl=urlobj.path htmlfiledir="html/finally/"+geturl.split('/')[1][0:2] if not os.path.exists(htmlfiledir): try: os.makedirs(htmlfiledir) except Exception,e: print e htmlfile=htmlfiledir+geturl if not os.path.exists(htmlfile): httpresult=sendhttp(geturl,urlobj.hostname,htmlfile) if httpresult: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",sent http request succ,Finallyurl:"+finallyurl else: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",sent http request fail,Finallyurl:"+finallyurl with open(htmlfile) as file: htmlcontent=file.read() parser= FinallPageParser() ##htmmparser遇到/>就表示tag結尾,所以必須替換,遇到<br/>替換爲BRBR,否則會解析失敗 htmlcontent=re.compile('<br/>').sub('BRBR',htmlcontent) parser.feed(htmlcontent) finalparseurl=parser.getdata() if finalparseurl: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",parse finalparseurl succ:"+finallyurl else: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",parse finalparseurl fail:"+finallyurl return finalparseurl #獲取圖片的方法 def getimg(imgdir,imgurl): imgobj=urlparse(imgurl) getimgurl=imgobj.path imgtmppathlist=getimgurl.split('/') imgname=imgtmppathlist[len(imgtmppathlist)-1] if not os.path.exists(imgdir): try: os.makedirs(imgdir) except Exception,e: print e savefile=imgdir+"/"+imgname if not os.path.exists(savefile): sendhttp_rult=sendhttp(getimgurl,imgobj.hostname,savefile) if sendhttp_rult: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",sent http request succ,getimg:"+imgurl else: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",sent http request fail,getimg:"+imgurl else: pass #獲取價格 def getprice(pricedir,priceurl): priceobj=urlparse(priceurl) getpriceurl=priceobj.path+"?"+priceobj.query pricename="price" if not os.path.exists(pricedir): try: os.makedirs(pricedir) except Exception,e: print e savefile=pricedir+"/"+pricename if not os.path.exists(savefile): sendhttp_rult=sendhttp(getpriceurl,priceobj.hostname,savefile) if sendhttp_rult: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",sent http request succ,getprice:"+priceurl else: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+",sent http request fail,getprice:"+priceurl else: pass with open(savefile) as file: price_content=file.read() price_content=re.compile('cnp\\(\\[|\\]\\);').sub('',price_content) price_dic={"id":"0","p":"0","m":"0"} if re.search(r':',price_content): try: price_dic=json.loads(price_content)#以免數據格式不對悲劇 except Exception,e: print e return {"jdprice":price_dic['p'],'refprice':price_dic['m']} #獲取最後頁面的具體內容 def getfinalurl_content(partlists,listpageurl,finalparseurl): parseFinallyurl_rult=parseFinallyurl(finalparseurl) htmlname_tmp=urlparse(finalparseurl).path imgtopdir_tmp="img/"+htmlname_tmp.split('/')[1][0:2] imgdir=imgtopdir_tmp+htmlname_tmp+"/introduction" imgshowdir=imgtopdir_tmp+htmlname_tmp+"/show" partdetail_tmp="" for imgurl in parseFinallyurl_rult['partimgs']:#獲取商品介紹的圖片 getimg(imgdir,imgurl) for imgshowurl in parseFinallyurl_rult['partimgs_show']:#獲取展示圖片 getimg(imgshowdir,imgshowurl) for key in parseFinallyurl_rult['partdetail'].keys(): partdetail_tmp=partdetail_tmp+key+"$$"+parseFinallyurl_rult['partdetail'][key]+","#商品介紹 specification_tmp="" i=0 for specification_var in parseFinallyurl_rult["specification"]:#規格參數 if i==0: str_slip="" elif(i%2==0 and i!=0 ): str_slip="," else: str_slip="$$" specification_tmp=specification_tmp+str_slip+specification_var i=i+1 typeOrsize_tmp="" for typeOrsize_var in parseFinallyurl_rult['typeOrsize']: typeOrsize_tmp=typeOrsize_tmp+","+typeOrsize_var priceurl="http://p.3.cn/prices/get?skuid=J_"+htmlname_tmp.split('/')[1].split('.')[0]+"&type=1&area=6_309_312&callback=cnp" pricedir="price/"+htmlname_tmp.split('/')[1][0:2]+htmlname_tmp getprice_dic=getprice(pricedir,priceurl) parseFinallyurl_rult["jdprice"]=getprice_dic['jdprice'] parseFinallyurl_rult["refprice"]=getprice_dic['refprice'] #partlists[listpageurl]):商品分類 #finalparseurl,頁面的url #parseFinallyurl_rult["title"]):標題 #parseFinallyurl_rult["jdprice"]:京東的價格 #parseFinallyurl_rult["refprice"]:市場參考價格 #imgshowdir:商品展示的圖片保存位置 #imgdir:商品說明的圖片保存位置:jd的商品說明也是用圖片的 #partdetail_tmp:商品的詳細信息 #specification_tmp:商品的規則參數 #typeOrsize_tmp:商品的類型和尺寸 return str(partlists[listpageurl]).strip()+"\t"+finalparseurl.strip()+"\t"+str(parseFinallyurl_rult["title"]).strip()+"\t"+str(parseFinallyurl_rult["jdprice"]).strip()\ +"\t"+str(parseFinallyurl_rult["refprice"]).strip()+"\t"+imgshowdir.strip()+"\t"+imgdir.strip()+"\t"+partdetail_tmp.strip()+"\t"+specification_tmp.strip()+"\t"+\ typeOrsize_tmp.strip() #判斷最後的頁面(商品詳情頁)是否被爬取了 def judgeurl(url):#優化後,使用二分法查找url(查找快了,同時也不用反覆讀取文件了)。第一次加載judgeurl_all_lines之後,維護好此list,同時新增的url也保存到judgeurl.txt中 url=url+"\n" global judgeurl_all_lines find_url_flag=False url_point=bisect.bisect(judgeurl_all_lines,url)#這裏使用二分法快速查找(前提:list是排序好的) find_url_flag = judgeurl_all_lines and judgeurl_all_lines[url_point-1] == url return find_url_flag #判斷list頁面是否已經爬取完畢了 #這裏的邏輯是:第一個list中的所有url、最後list的所有url都爬取完畢了,那麼久說明list的所有page爬取完畢了(實際上是一種弱校驗)。 #調用了judgeurl得方法 def judgelist(listpageurl,finallylistpageurl):#判斷第一個、最後一個的list頁面的所有的html是否下載完畢,以此判斷該類型是否處理完畢 judgelist_flag=True parseListpageurl_rult_finally=parseListpageurl(finallylistpageurl) finalparseurls_deep_finally=list(parseListpageurl_rult_finally['finalparseurls'])#獲取到最後的需要解析的url的列表 parseListpageurl_rult_first=parseListpageurl(listpageurl) finalparseurls_deep_first=list(parseListpageurl_rult_first['finalparseurls'])#獲取到最後的需要解析的url的列表 for finalparseurl in finalparseurls_deep_finally: #print finalparseurl if judgeurl(finalparseurl): pass else: judgelist_flag=False break if judgelist_flag==True: for finalparseurl_first in finalparseurls_deep_first: #print finalparseurl if judgeurl(finalparseurl_first): pass else: judgelist_flag=False break return judgelist_flag #整體控制的run方法 def run(): partlists={'http://list.jd.com/list.html?cat=737,794,870':'空調'} partlistskeys=partlists.keys() for listpageurl in partlistskeys: parseListpageurl_rult=parseListpageurl(listpageurl)#開始解析list頁面,如:http://list.jd.com/list.html?cat=737,794,870 totalPageNo=parseListpageurl_rult['totalPageNo']#獲取該list總共有多少頁 #print 'debug:totalPageNo',totalPageNo finallylistpageurl=listpageurl+'&page='+str(int(totalPageNo)+1)+'&JL=6_0_0'#拼接出最後一個list頁面(list頁面有1、2、3。。。n頁) #print 'debug:finallylistpageurl ',finallylistpageurl if judgelist(listpageurl,finallylistpageurl):#如果該list已經爬取完畢了。那麼,就跳過這個list print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+',All html done for '+str(listpageurl)+":"+str(partlists[listpageurl])+"【Done Done】,【^_^】" continue else:#否則就逐個沿着list,從其第1頁,開始往下爬取 for i in range(1,int(totalPageNo)+2): finalparseurl='' listpageurl_next=listpageurl+'&page='+str(i)+'&JL=6_0_0' #print "debug:listpageurl_next",listpageurl_next parseListpageurl_rult=parseListpageurl(listpageurl_next) totalPageNo=parseListpageurl_rult['totalPageNo']#需要更行總的頁面數量,以免數據陳舊 finalparseurls_deep=list(parseListpageurl_rult['finalparseurls']) for finalparseurl in finalparseurls_deep: if judgeurl(finalparseurl):#判斷該具體的url是否已經爬取 print 'finalparseurl pass yet:'+finalparseurl pass else: finalurl_content=getfinalurl_content(partlists,listpageurl,finalparseurl) finalparseurl_tmp=finalparseurl+"\n" with open("data.txt","a") as datafile:#將爬取完畢好的url寫入data.txt datafile.writelines(finalurl_content+"\n") with open("judgeurl.txt","a") as judgefile:#將已經爬取好的url寫入judgeurl.txt judgefile.writelines(finalparseurl+"\n") bisect.insort_right(judgeurl_all_lines,finalparseurl+"\n") #主方法 if __name__ == '__main__': reload(sys) sys.setdefaultencoding('utf8')#設置系統默認編碼是utf8 socket.setdefaulttimeout(5)#設置全局超時時間 global judgeurl_all_lines#設置全局變量 #不存在文件就創建文件,該文件用於記錄哪些url是爬取過的,如果臨時中斷了,可以直接重啓腳本即可 if not os.path.exists("judgeurl.txt"): with open("judgeurl.txt",'w') as judgefile: judgefile.close() #每次運行只在開始的時候讀取一次,新產生的數據(已怕去過的url)也會保存到judgeurl.txt with open("judgeurl.txt","r") as judgefile: judgeurl_all_lines=judgefile.readlines() judgeurl_all_lines.sort()#排序,因爲後面需要使用到二分查找,必須先排序 #啓多個線程去爬取 Thread(target=run(),args=()).start() Thread(target=run(),args=()).start() #Thread(target=run(),args=()).start()