创建编码一个spider的具体步骤
程序员文章站
2022-07-13 22:50:06
...
为使项目框架结构清晰,添加的spider的按城市划分存储位置。
例如宁波新闻网—综合频道,则在spiders下面建一个ningbo(宁波)的文件夹,将该版面的spider写在该文件夹下面。
项目设计框架图:
实际项目tree图片见附件tree.jpg
webcrawler:. |——scrapy.cfg |——webcrawler: |——items.py |——pipelines.py |——settings.py |——__init__.py |——spiders |__init__.py |——cityAAA |——website_channel_type_id_spider|——cityBBB |——website_channel_type_id_spider |——city*** *** |——increment |——cityAAA |——website_channel_type_id.txt |——cityBBB |——website_channel_type_id_.txt |——city*** *** |——logs(待实现) |——cityAAA |——website_channel_type_id.log |——cityBBB |——website_channel_type_id.log |——warnlog |——warn.log
数据的存储位置在spider中指定
spider的创建步骤(以环球网--海外看中国版面为例):
1.在所在城市的文件加下创建spider(eg:环球网--海外看中国)
在spiders下面创建文件夹,名称为(quanguo)全国:
mkdir quanguo进入文件夹,在文件夹下创建**_spider,命名规则为website_channel_type_id_spider.py,:
cd quanguo vim huanqiu_oversea_new_1_spider.py再创建一个名称为__init__.py的文件,该文件是运行py的必需文件,创建命令为:
touch __init__.py2.进入创建的spider文件中,导入程序所需的包:
#coding=utf-8 import sys sys.path.insert(0,'..') import scrapy import time import os import hashlib import struct from scrapy import Spider import sys from webcrawler.items import TextDetailItem reload(sys) sys.setdefaultencoding('gbk')3.设置参数,包括增量文件的位置,存储增量的incrementurls变量,首次采集的数量,文件存储的位置,日志存储的位置。
incrementurl=[] indexUrl='' fListNum=0 firstCrawlerNum=100 incrementfile="/download/Scrapy-1.0.1/webcrawler/webcrawler/increment/quanguo/huanqiu_oversea_new_1.txt" sourceDefault="环球网--海外看中国" savefile="/download/datastore/"4.创建spider类,继承自Spider,并设置spider的运行name,allowed_urls,start_urls,保存采集数据的文件名称,读取增量文件获取urls(用于采集增量爬取数据,防止数据重复)
name="huanqiu_oversea_new_1_spider" allowed_urls=["oversea.huanqiu.com"] start_urls=["http://oversea.huanqiu.com/"] #fetch time start tempa=time.strftime('%Y-%m-%d',time.localtime(time.time())) filename=time.mktime(time.strptime(tempa,'%Y-%m-%d')) filename=str(filename)[0:10] global savefile savefile+="news_doc_incoming_1_"+filename #fetch time end #Read increment file start global indexUrl global incrementfile global incrementurl indexUrl="http://oversea.huanqiu.com/" indexUrl=start_urls[0] if os.path.isfile(incrementfile): print('file have exist...') else: f=open(incrementfile,"w") f.close() furl = open(incrementfile, "r") while True: line = furl.readline() if line=='': break else: incrementurl.append(line.strip('\n')) furl.close() #Read increment file end5.重写__init__函数,此函数继承自Spider,可不写,第四部的编码也可以写到该函数当中
def __init__(self): print('init...')6.编写parse(self,response)函数,对列表页的数据进行爬取,包括:
1.获取列表url
2).获取下一页的url
3).下一页的判断逻辑
4).判断url是否在增量中存在,若存在说明后面的数据已经采集过,break
5).根据url获取其详情页的内容
6).设置首次采集的数量,因为很多列表数据是分页的,首次采集无增量,采集的数据可能非常多
7).将第一页的列表url数据存储为增量url
8).进入列表页下一页的采集
def parse(self,response): global indexUrl global fListNum global firstCrawlerNum #获取请求的url,即(start_urls) pUrl=str(response.url) sel=scrapy.Selector(response) #定义获取列表url list=sel.xpath("//div[@class='leftList']/ul[@name='contentList']/li[@name='item']") print(str(len(list))) #获取下一页的url nextUrl=sel.xpath("//div[@class='turnPage']/a/@href").extract() #下一页的判断逻辑 if nextUrl is not None and len(nextUrl)>1: nextPage=nextUrl[1] elif nextUrl is not None and len(nextUrl)>0: nextPage=nextUrl[0].encode('utf-8') else: nextPage=None #定义增量标志 flag='0' #依次获取列表中的每隔url,title可不提取,只为测试方便 for single in list: title=single.xpath("a/dl/dt/h3/text()").extract() url=single.xpath("a/@href").extract() tempurl=url[0].encode('utf-8') detailurl=tempurl print(detailurl) #判断该url是否在增量中存在,若存在说明后面的数据已经采集过,break if detailurl in incrementurl: flag='1' break else: #根据url获取其详情页的内容 reqdetail=scrapy.Request(url=detailurl,meta={'pUrl':pUrl},callback=self.parse_detail) yield reqdetail #设置首次采集的数量,因为很多列表数据是分页的,首次采集无增量,采集的数据可能非常多 if len(incrementurl)==0: fListNum+=len(list) if(fListNum>firstCrawlerNum): return #将第一页的列表url数据存储为增量url if indexUrl==str(response.url): writeStr='' for tSingle in list: tUrl=tSingle.xpath("a/@href").extract() ttUrl=tUrl[0].encode('utf-8') writeStr+=ttUrl+'\n' open(incrementfile,'w').write(writeStr+'\n') #进入列表页下一页的采集 if flag=='0': if nextPage is not None: req = scrapy.Request(url=nextPage, callback=self.parse) yield req else: return
7. 定义详情页采集函数,设置提取详情页数据的规则,将数据放进对象容器,供pipline存储
def parse_detail(self,response): global savefile global sourceDefault #创建数据容器对象,用于存储采集的数据 textDetail=TextDetailItem() sel=scrapy.Selector(response) #定义提取详情页标题,来源,发布时间,正文的规则 title=sel.xpath("//div[@class='conText']/h1/text()").extract() source=sel.xpath("//*[@id='source_baidu']/a/text()").extract() source2=sel.xpath("//*[@id='source_baidu']/text()").extract() tTime=sel.xpath("//strong[@id='pubtime_baidu']/text()").extract() contents=sel.xpath("//div[@id='text']/p").extract() url=response.url if not url: return else: #根据详情页url生成MD tmp_msg_id = hashlib.md5(url).hexdigest()[0:8] msg_id = long(struct.unpack('Q',tmp_msg_id)[0]) MD=msg_id textDetail['MD']=str(MD) textDetail['CL']="news" textDetail['UR']=str(url) PR=response.meta['pUrl'] textDetail['PR']=str(PR) FC="0" textDetail['FC']=FC HR=str(response.status) textDetail['HR']=HR ET="0" textDetail['ET']=ET RT="1" textDetail['RT']=RT title=title[0].encode('utf-8') print("text title:"+str(title)) textDetail['TI']=title SR= sourceDefault if len(source)>0: SR=source[0].encode('utf-8') else: if len(source2)>0: SRstr=source2[0].encode('utf-8') SRstr=SRstr.replace("\r\n","") SRstr=SRstr.strip() SR=SRstr[9:] textDetail['SR']=SR imageurls='' imageurls='' #提取正文中的图片链接 imagelist=sel.xpath("//div[@id='text']/*/img[@src]/@src").extract() for i in range(len(imagelist)): if i==len(imagelist)-1: imageurls+=imagelist[i] else: imageurls+=imagelist[i]+'|' imageurls=imageurls.strip() textDetail['IU']=str(imageurls) textDetail['KW']="" temptime=tTime[0].strip() temptime=time.mktime(time.strptime(temptime,'%Y-%m-%d %H:%M:%S')) PT=(str(temptime))[0:10] textDetail['PT']=PT dTime=time.time() DT=(str(dTime))[0:10] textDetail['DT']=DT textDetail['TY']="" content="" for i in range(0, len(contents)): content+=contents[i].encode('utf-8') # content=content[0].encode('utf-8') TX=content textDetail['TX']=TX textDetail['SP']=savefile return textDetail
8.一次运行scrapy下所有spider的方法:查找资料后编写了一个crawlall.py,该python脚本能够获取到scrapy框架下所有的可运行的spider,并启动它,crawlall脚本代码如下:
from scrapy.commands import ScrapyCommand from scrapy.crawler import CrawlerRunner from scrapy.utils.conf import arglist_to_dict class Command(ScrapyCommand): requires_project = True def syntax(self): return '[options]' def short_desc(self): return 'Runs all of the spiders' def add_options(self, parser): ScrapyCommand.add_options(self, parser) parser.add_option("-a", dest="spargs", action="append", default=[], metavar="NAME=VALUE", help="set spider argument (may be repeated)") parser.add_option("-o", "--output", metavar="FILE", help="dump scraped items into FILE (use - for stdout)") parser.add_option("-t", "--output-format", metavar="FORMAT", help="format to use for dumping items with -o") def process_options(self, args, opts): ScrapyCommand.process_options(self, args, opts) try: opts.spargs = arglist_to_dict(opts.spargs) except ValueError: raise UsageError("Invalid -a value, use -a NAME=VALUE", print_help=False) def run(self, args, opts): #settings = get_project_settings() spider_loader = self.crawler_process.spider_loader for spidername in args or spider_loader.list(): print "*********cralall spidername************" + spidername self.crawler_process.crawl(spidername, **opts.spargs) self.crawler_process.start()
9.可持续运行的shell脚本runspider.sh,通过运行脚本可持续的运行crawlall.py,runspider.sh脚本内容如下:
#!/bin/sh int=1 while((1)) do echo $int scrapy crawlall let "int++" done
上一篇: scrapy缺省配置 scrapy爬虫
下一篇: scrapy 抓的段子里的 \n 去不掉