欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

创建编码一个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__.py
2.进入创建的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 end
 5.重写__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 Spider