首页 python爬虫实战

python爬虫实战

举报
开通vip

python爬虫实战python爬虫实战,多线程爬取京东jdhtml页面:无需登录的网站的爬虫实战2014-12-0220:04:31标签:网站爬虫pythonimport版权声明:原创作品,如需转载,请与作者联系。否则将追究法律责任。【前言】i2#本脚本仅用于技术交流,请3勿用于其他用途4#byRiver5#Date:2014-12-0219:00:006【需求说明】以京东为示例,爬取页面的,获取页面中得数据:记录到data.txt;获取页面中得图片,保存下来。1、list的url如下2、商品详情页的url如下:【技术说明】1使用了...

python爬虫实战
python爬虫实战,多线程爬取京东jdhtml页面:无需登录的网站的爬虫实战2014-12-0220:04:31标签:网站爬虫pythonimport版权声明:原创作品,如需转载,请与作者联系。否则将追究法律 责任 安全质量包保责任状安全管理目标责任状8安全事故责任追究制幼儿园安全责任状占有损害赔偿请求权 。【前言】i2#本脚本仅用于技术交流,请3勿用于其他用途4#byRiver5#Date:2014-12-0219:00:006【需求说明】以京东为示例,爬取页面的,获取页面中得数据: 记录 混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载 到data.txt;获取页面中得图片,保存下来。1、list的url如下2、商品详情页的url如下:【技术说明】1使用了python的以下库importos#检查文件是否存在等3fromHTMLParserimportHTMLParser#45用于解析html的库,有坑:如果2.656的python,可能悲剧7importhttplib,re#发起http请求importsys,json,datetime,bisect#使用了二分快速查找fromurlparseimporturlparse#解析url, 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 出url的各部分功能fromthreadingimportThread#使用多线程importsocket#设置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的内容,如果存在一些特殊字符,可能需要替换,否则解析出来会莫名不PAGE\*MERGEFORMAT#4、图片保存,根据url获取前面两个数字,保存。以免一个 目录 工贸企业有限空间作业目录特种设备作业人员作业种类与目录特种设备作业人员目录1类医疗器械目录高值医用耗材参考目录 下保存了过多的图片。执行结果】1、console输出2、data.txt存储解析出来的内容3、judegurl.txt(保存已经爬取过的url)4、图片(下载的图片)代码详情】#-*-coding:utf-8-*-__author__二'River'#本脚本仅用于技术交流,请勿用于其他用途#byRiver#Date:2014-12-0219:00:0078910112134:1:importos#创建文件fromHTMLParserimportHTMLParser#用于解析html的库,有坑:如果2.6的python,可能悲剧importhttplib,re#发起http请求importsys,json,datetime,bisect#使用了二分快速查找fromurlparseimporturlparse#解析url,分析出url的各部分功能fromthreadingimportThread#使用多线程importsocket#设置httplib超时时间#htmlparser的使用简介#定义intt方法:需要使用到得属性#定义handle_starttag,处理你想分析的tag的具体操作5#定义handle_data,遇到你定义的情况,获取相应标签的data#定义你获取最终返回的各种数据classListPageParser(HTMLParser):PAGE\*MERGEFORMAT#7181920212223242526272829303132333435363738def__init__(self):self.handledtags二['a']self.processing二Noneself.flag二'’self.link二'’self.setlinks二set()##该list页面中包含的每个商品的url,定义为set,主要是为了使用其特性:去重self.pageNo=lself.alldata=[]HTMLParser.__init__(self)defhandle_starttag(self,tag,attrs):pattern二re.compile(r'"[0-9]{2,}')#attrs是属性的list,每个属性(包含key,value)又是一个元组#已上为例子:判断了该list的长度为3(其他的a标签就被过滤了)iftaginself.handledtagsandlen(attrs)==3:#非常关键的是,找出你想的url和不想要的url的区别#print"debug:attrs",attrsself.flag二'’self.data二''self.processing二tagfortarget,hrefinattrs:#非常关键的是,找出你想的url和不想要的url的区别ifpattern2.match(href):#再加一层判断,如果匹配上pattern2,说明是我们想要的urlelse:pass#1、长度为1#2,href是由规则的:cat=737%2C794%2C798&page=10&JL=6_0_0,所以,以下代码就出来了iftaginself.handledtagsandlen(attrs)==1:self.flag二'’self.data二''self.processing二tagforhref,urlinattrs:#非常关键的是,找出你想的url和不想要的url的区别#print'debug:attrs',attrsPAGE\*MERGEFORMAT#9404142434445464748495051525354555657585960ifpattern3.match(url):#print'debug:url',urlself.lasturl二urlelse:passdefhandle_data(self,data):ifself.processing:#去掉空格pass#其实这里我们根本没使用获取到得data,就pass把else:passdefhandle_endtag(self,tag):iftag二二self.processing:self.processing二Nonedefgetlinks(self):returnself.setlinksdefgetlasturl(self):returnself.lasturl#FinallPageParser的定义过程参考上个parser,关键是怎样分析页面,最终写出代码,并且验证,这里就不详细说了classFinallPageParser(HTMLParser):def__init__(self):self.handledtags二['div','hl','strong','a','del','div','img',Ti','span,,,tbody,,,tr,,,th,,,td,,,i,]self.processing二Noneself.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,]=,,PAGE\*MERGEFORMAT#1626364656667686970717273747576777879808182self.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)defhandle_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']二'’iftaginself.handledtags:self.data二''self.processing二tagiftag=='div':forkey,valueinattrs:self.div二value#取出div的name,判断是否是所需要的图片等元素iftag=='i':self.flag['typeOrsize']二'match'iftag=='a'andlen(attrs)==2:tmpflag二〃〃forkey,valueinattrs:ifkey二二'href'andtmpflag二"first〃ifkey=二'title'andvalue!二〃〃:tmpflag二tmpflag+〃second〃PAGE\*MERGEFORMAT#3848586878889909192939495969798991001011021iftmpflag二二"firstsecond":self.flag['typeOrsize']二'match'iftag=='h1':self.flag['title']='match'iftag=='strong'andlen(attrs)==2:fortmpclass,idinattrs:ifid==jd—price:self.flag['jdprice']='match'iftag=='del':self.flag['refprice']='match'iftag=='li':self.flag['partdetail']='match'iftag=='th'ortag=='tr'ortag=='td':#++++++++############################################879498.htmltd中有br的只取到第一个,需要把
喜欢为“”self.flag['specification']二'match'iftag=='img':imgtmp_flag二,,imgtmp二,,forkey,valueinattrs:if(key=='src'orkey=='data—lazyload'):imgtmp二valueifkey=='width':############可能还有logoifre.search(r'飞d{l,9}$',value):ifint(value)<=160:imgtmp_flag二'no'breakifself.div二二"spec-items"andimgtmp!二'':imgtmp二re.compile("/n5/").sub("/nl/",imgtmp)self.partimgs_show.add(imgtmp)elifimgtmp_flag!二'no'andimgtmp!二'':defhandle_data(self,data):ifself.processing:self.data+二dataifself.flag['title']=='match':#获取成功1041051061071081091101111121131141151161171.title=dataifself.flag['jdprice']二二'match':self.jdprice二data.strip()ifself.flag['typeOrsize']二二'match':ifself.flag['refprice']=='match':self.refprice二data.strip()ifself.flag['partdetail']=='match'andre.search(r':',data):#获取成功valuetmp二data.split(":")[1].strip()self.partdetail[keytmp]二valuetmpifself.flag['specification']=='match'anddata.strip()!=''anddata.strip()!='主体’:else:pass.split(":")[0].strip()defhandle_endtag(self,tag):iftag二二self.processing:self.processing二Nonedefgetdata(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的获取内容#这也是代码抽象的结果,如若不抽象这块代码出来,后续你回发现很多重复defhttpread(host,url,headers):httprestmp二''try:conn二httplib.HTTPConnection(host)conn.request('GET',url,None,headers)httpres二conn.getresponse().read()exceptException,e:conn=httplib.HTTPConnection(host)conn.request('GET',url,None,headers)httpres二conn.getresponse()181191201211221231241251261271281291301311httprestmp二httpres.read()printefinally:ifconn:conn.close()returnhttprestmp#定义方法sendhttp,调用httpread,获取结果并替换编码(gbk换为utf-8),并保存到文件中(以免下次再去下载页面,这样就节省了时间)#defsendhttp(url,host,savefile):#定义http头部,很多网站对于你不携带User-Agent及Referer等情况,是不允许你爬取。#具体的http的头部有些啥信息,你可以看chrome,右键审查元素,点击network,点击其中一个链接,查看requestheaderheaders二{"Host":host,"Content-type":"application/x-www-form-urlencoded;charset二UTF-8","Accept":"text/html;q=0.9,image/webp,*/*;q=0.8",}httprestmp二''httprestmp二httpread(host,url,headers)ifhttprestmp二二'':#httprestmp二httpread(host,url,headers)ifhttprestmp二二'’:#重试2次httprestmp二httpread(host,url,headers)exceptException,e:try:httprestmp二httpread(host,url,headers)ifhttprestmp二二'':#httprestmp二httpread(host,url,headers)ifhttprestmp二二'’:#重试2次httprestmp二httpread(host,url,headers)exceptException,e:printe13i3413i313713813914014114214314414514614printeifre.search(r'charset=gb2312',httprestmp):#如果是gb2312得编码,就要转码为utf-8(因为全局都使用了utf-8).replace("charset二gb2312",'charset二utf—8')try:httprestmp二httprestmp.decode('gbk').encode('utf—8')#有可能转码失败,所以要加上tryexceptException,e:#如果html编码本来就是utf8或者转换编码出错的时候,就啥都不做,就用原始内容printetry:withopen(savefile,'w')asfile_object:file_object.write(httprestmp)file_object.flush()exceptException,e:returnhttprestmp#list的页面的解析方法defparseListpageurl(listpageurl):urlobj=urlparse(listpageurl)ifurlobj.query:geturl二urlobj.path+""+urlobj.queryelse:geturl二urlobj.pathhtmlfile="html/list"+geturlifnothttpresult二sendhttp(geturl,urlobj.hostname,htmlfile)withopen(htmlfile)asfile:htmlcontent二file.read()parser二ListPageParser()#声明一个解析对象.feed(htmlcontent.replace('amp;',''))#将html的内容feed进去#print'debug:htmlcontent',htmlcontentfinalparseurl二parser.getlinks()#然后get数据即可lastpageurl二parser.getlasturl()urlobj_lastpageurl二urlparse(lastpageurl)71481491501511521515415151571581591601611#print'debug:urlobj_lastpageurl',urlobj_lastpageurltotalPageNo二'O'#printurlobjifre.search(r'&',urlobj_lastpageurl.query):try:exceptException,e:print"lastpageurl:"+str(lastpageurl)printeparseListpageurl_rult二{'finalparseurls':finalparseurl,‘totalPageNo':totalPageNo}ifparseListpageurl_rult['finalparseurls']!二""andparseListpageurl_rult['totalPageNo']!='':printelse:print-%m-%d%H:%M:%S")+",parselistpageurlfail:"+listpageurlreturnparseListpageurl_rult#最终的html页面的解析方法:会使用到html得解析器FinallPageParserdefparseFinallyurl(finallyurl):urlobj二urlparse(finallyurl)geturl二urlobj.pathhtmlfiledir="html/finally/"+geturl.split('/')[1][0:2]ifnottry:.makedirs(htmlfiledir)exceptException,e:printehtmlfile=htmlfiledir+geturlifnot,urlobj.hostname,htmlfile)ifhttpresult:printelse:printwithopen(htmlfile)asfile:htmlcontent二file.read()216i6416i61671681691701711721731741751##htmmparser遇到/>就表示tag结尾,所以必须替换,遇到<br/>替换为BRBR,否则会解析失败htmlcontent二re.compile('
').sub('BRBR',htmlcontent)parser.feed(htmlcontent)finalparseurl二parser.getdata()iffinalparseurl:printelse:printreturnfinalparseurl#获取图片的方法defgetimg(imgdir,imgurl):imgobj二urlparse(imgurl)getimgurl二imgobj.pathimgtmppathlist二getimgurl.split('/')imgname=imgtmppathlist[len(imgtmppathlist)T]ifnottry:os.makedirs(imgdir)exceptException,e:printesavefile二imgdir+"/"+imgnameifnotsendhttp_rult二sendhttp(getimgurl,imgobj.hostname,savefile)ifsendhttp_rult:printse:printelse:pass#获取价格defgetprice(pricedir,priceurl):priceobj二urlparse(priceurl)getpriceurl二priceobj.path+""+priceobj.queryPAGE\*MERGEFORMAT#1771781791801811821831841851861871881891901•〃・〃pricename二priceifnottry:os.makedirs(pricedir)exceptException,e:printesavefile二pricedir+"/"+pricenameifnotsendhttp_rult二sendhttp(getpriceurl,priceobj.hostname,savefile)ifsendhttp_rult:printelse:printelse:passwithopen(savefile)asfile:price_content二file.read()price_content二re.compile('cnp\\(\\[|\\]\\);').sub('',price_content)price_dic={id:0,p:0,m:0}ifre.search(r':',price_content):try:price_dic=json.loads(price_content)#以免数据格式不对悲剧exceptException,e:printereturn{"jdprice":price_dic['p'],'refprice':price_dic['m']}#获取最后页面的具体内容defgetfinalurl_content(partlists,listpageurlfinalparseurl):parseFinallyurl_rult二parseFinallyurl(finalparseurl)htmlname_tmp二urlparse(finalparseurl).pathimgtopdir_tmp="img/"+htmlname_tmp.split('/')[l][0:2]imgdir=imgtopdir_tmp+htmlname_tmp+"/introduction"imgshowdir二imgtopdir_tmp+htmlname_tmp+"/show"partdetail_tmp二""forimgurlinparseFinallyurl_rult['partimgs']:#获取商品介绍的图片getimg(imgdir,imgurl)PAGE\*MERGEFORMAT#1192193194195196197198199200201202203204205forimgshowurlinparseFinallyurl_rult['partimgs_show']:#获取展示图片getimg(imgshowdir,imgshowurl)forkeyinparseFinallyurl_rult['partdetail'].keys():partdetail_tmp二partdetail_tmp+key+"$$"+parseFinallyurl_rult['partdetail'][key]+〃,〃#商品介绍specification_tmp二〃〃i=0forspecification_varinparseFinallyurl_rult["specification〃]:#规格参数ifi==0:str_slip二〃〃elif(i%2==0andi!=0):str_slip二〃,〃else:str_slip二〃$$〃specification_tmp=specification_tmp+str_slip+specification_vari=i+1typeOrsize_tmp二〃〃fortypeOrsize_varinparseFinallyurl_rult['typeOrsize']:typeOrsize_tmp二typeOrsize_tmp+〃,〃+typeOrsize_varpricedir二〃price/〃+htmlname_tmp.split('/')[l][0:2]+htmlname_tmpgetprice_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:商品的类型和尺寸returnstr(partlists[listpageurl]).strip()+〃\t〃+finalparseurl.strip(3PAGE\*MERGEFORMAT#0620720820921021121221321421521621721821922)+"\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()#判断最后的页面(商品详情页)是否被爬取了defjudgeurl(url):#优化后,使用二分法查找url(查找快了,同时也不用反复读取文件了)。第一次加载judgeurl_all_lines之后,维护好此list,同时新增的url也保存到judgeurl.txt中url=url+"\n"globaljudgeurl_all_linesfind_url_flag二Falseurl_point二bisect.bisect(judgeurl_all_lines,url)#这里使用二分法快速查找(前提:list是排序好的)find_url_flag=judgeurl_all_linesandjudgeurl_all_lines[url_point-l]=二urlreturnfind_url_flag#判断list页面是否已经爬取完毕了#这里的逻辑是:第一个list中的所有url、最后list的所有url都爬取完毕了,那么久说明list的所有page爬取完毕了(实际上是一种弱校验)。#调用了judgeurl得方法defjudgelist(listpageurl,finallylistpageurl):#判断第一个、最后一个的list页面的所有的html是否下载完毕,以此判断该类型是否处理完毕judgelist_flag二TrueparseListpageurl_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的列表forfinalparseurlinfinalparseurls_deep_finally:#printfinalparseurlifjudgeurl(finalparseurl):pass2212222232242252262272282292302312322332342else:judgelist_flag二Falsebreakifjudgelist_flag二二True:forfinalparseurl_firstinfinalparseurls_deep_first:#printfinalparseurlifjudgeurl(finalparseurl_first):passelse:judgelist_flag二Falsebreakreturnjudgelist_flag#整体控制的run方法defrun():partlistskeys二partlists.keys()forlistpageurlinpartlistskeys:totalPageNo二parseListpageurl_rult['totalPageNo']#获取该list总共有多少页#print'debug:totalPageNo',totalPageNofinallylistpageurl=listpageurl+'&page二'+str(int(totalPageNo)+1)+'&JL=6_0_0'#拼接出最后一个list页面(list页面有1、2、3。。°n页)#print'debug:finallylistpageurl',finallylistpageurlifjudgelist(listpageurl,finallylistpageurl):#如果该list已经爬取完毕了。那么,就跳过这个listprintcontinueelse:#否则就逐个沿着list,从其第1页,开始往下爬取foriinrange(1,int(totalPageNo)+2):finalparseurl二''listpageurl_next二listpageurl+'&page='+str(i)+'&JL=6_0_0'#print"debug:listpageurl_next",listpageurl_nextparseListpageurl_rult二parseListpageurl(listpageurl_next)totalPageNo二parseListpageurl_rult['totalPageNo']#需要更行总的页面数量,以免数据陈旧finalparseurls_deep=list(parseListpageurl_rult['finalparseurls'])PAGE\*MERGEFORMAT#5236237238239240241242243244245246247248249forfinalparseurlinfinalparseurls_deep:ifjudgeurl(finalparseurl):#判断该具体的url是否已经爬取print'finalparseurlpassyet:'+finalparseurlpasselse:finalurl_content二getfinalurl_content(partlists,listpageurl,finalparseurl)finalparseurl_tmp=finalparseurl+"\n"withopen("data.txt","a")asdatafile:#将爬取完毕好的url写入data.txtdatafile.writelines(finalurl_content+"\n")withopen("judgeurl.txt","a")asjudgefile:#将已经爬取好的url写入judgeurl.txtjudgefile.writelines(finalparseurl+"\n")bisect.insort_right(judgeurl_all_lines,finalparseurl+"\n")#主方法if__name__==__main__:reload(sys)sys.setdefaultencoding('utf8')#设置系统默认编码是utf8socket.setdefaulttimeout(5)#设置全局超时时间globaljudgeurl_all_lines#设置全局变量#不存在文件就创建文件,该文件用于记录哪些url是爬取过的,如果临时中断了,可以直接重启脚本即可ifnotwithopen("judgeurl.txt",‘w')asjudgefile:judgefile.close()#每次运行只在开始的时候读取一次,新产生的数据(已怕去过的url)也会保存到judgeurl.txtwithopen("judgeurl.txt","r")asjudgefile:judgeurl_all_lines=judgefile.readlines()judgeurl_all_lines.sort()#排序,因为后面需要使用到二分查找,必须先排序#启多个线程去爬取Thread(target二run(),args=()).start()Thread(target二run(),args=()).start()#Thread(target二run(),args=()).start()
本文档为【python爬虫实战】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
个人认证用户
映日荷花
暂无简介~
格式:doc
大小:153KB
软件:Word
页数:35
分类:
上传时间:2023-01-18
浏览量:0