本篇是python实例编写:糗事百科 ,目的是介绍最基础的scrapy框架的写法和运行过程。
 
 
功能描述 目标:获取 糗事百科 所所有信息的作者,url和内容,需要爬取多个页面,/page/1~/page/13。 
输出:保存到文件中(json格式)
编写步骤 编写spider 处理链接爬取和页面解析,编写pipelines 处理信息存储
步骤1:建立工程和Spider模板 1 2 3 \>scrapy startproject qsbk \>cd BaiduStocks \>scrapy genspider qsbk_spider qiushibaike.com 
 
步骤2:编写Spider 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 import  scrapyfrom  urllib.parse import  urljoinfrom  qsbk.items import  QsbkItemclass  QsbkSpiderSpider (scrapy.Spider) :    name = 'qsbk_spider'      allowed_domains = ['qiushibaike.com' ]     start_urls = ['http://qiushibaike.com/text/page/1/' ]     def  parse (self, response) :                  duanziDivs = response.xpath("//div[@class='col1 old-style-col1']/div" )         i = 0          for  div in  duanziDivs:                                       author = div.xpath(".//h2/text()" ).get().strip()                                                    href = div.xpath('./a/@href' ).get()              url = urljoin(self.start_urls[0 ],href)              content = div.xpath(".//div[@class='content']//text()" ).extract()                          content = '' .join(content).strip()                                                                              item = QsbkItem(author=author, content=content)             i += 1              print('生成器调用:' ,i)                          yield  item                                                                  
 
测试该函数可以注释最后的生成器步骤,取消注释前面的打印函数。
 
对setting.py的设置 1 2 3 4 5 user-agent = 'Mozilla/5.0'   ROBOTSTXT_OBEY = False   LOG_LEVEL = "WARN"   
 
步骤3:编写ITEM Pipelines 注意该文件中,类里的三个方法: 打开、运行、关闭。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from  itemadapter import  ItemAdapterimport  jsonclass  QsbkPipeline :    def  __init__ (self) :         self.fp = open('duanzi.json' , 'w' , encoding='utf-8' )          def  open_spider (self, spider) :         print('--------> 爬虫开始了... <---------' )          def  process_item (self, item, spider) :                  item_json = json.dumps(dict(item),ensure_ascii=False )          self.fp.write(item_json + '\n' )         print('pipelines调用' )         return  item          def  close_spider (self, spider) :         self.fp.close()         print('--------> 爬虫结束了... <---------' ) 
 
items.py编写 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import  scrapyclass  QsbkItem (scrapy.Item) :                   author = scrapy.Field()      content = scrapy.Field() 
 
注意 若要使用ITEM Pipelines,需要在setting.py中开启。
1 2 3 4 5 ITEM_PIPELINES = {    'qsbk.pipelines.QsbkPipeline' : 300 ,  } 
 
优化数据存储的方式 方法一:使用JsonItemExporter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from  scrapy.exporters import  JsonItemExporter class  QsbkPipeline :    def  __init__ (self) :         self.fp = open('duanzi.json' , 'wb' )          self.exporter = JsonItemExporter(self.fp, ensure_ascii = False , encoding = 'utf-8' )         self.exporter.start_exporting()          def  open_spider (self, spider) :         print('--------> 爬虫开始了... <---------' )     def  process_item (self, item, spider) :         self.exporter.export_item(item)         print('pipelines调用' )         return  item     def  close_spider (self, spider) :         self.exporter.finish_exporting()          self.fp.close()         print('--------> 爬虫结束了... <---------' ) 
 
缺点:所有item存在一个列表中,一起写入文件,较消耗内存。
            需要 开始 和 结束 。
但整体满足格式要求,一个大列表,每个元素是一个item的json格式数据。
 
方法二:使用JsonLinesItemExporter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from  scrapy.exporters import  JsonLinesItemExporterclass  QsbkPipeline :    def  __init__ (self) :         self.fp = open('duanzi.json' , 'wb' )          self.exporter = JsonLinesItemExporter(self.fp, ensure_ascii = False , encoding = 'utf-8' )     def  open_spider (self, spider) :         print('--------> 爬虫开始了... <---------' )     def  process_item (self, item, spider) :         self.exporter.export_item(item)         print('pipelines调用' )          return  item     def  close_spider (self, spider) :         self.fp.close()         print('--------> 爬虫结束了... <---------' ) 
 
此方法把每个item作为一个单独的字典类型存入文件。
不需要 开始 和 结束 。
缺点:每行数据为一个字典(json格式),但整个文件并不满足json格式。
 
抓取多个页面 主要是最后几行代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import  scrapyfrom  urllib.parse import  urljoinfrom  qsbk.items import  QsbkItemclass  QsbkSpiderSpider (scrapy.Spider) :    name = 'qsbk_spider'      allowed_domains = ['qiushibaike.com' ]     start_urls = ['http://qiushibaike.com/text/page/1/' ]     def  parse (self, response) :         duanziDivs = response.xpath("//div[@class='col1 old-style-col1']/div" )         i = 0          for  div in  duanziDivs:             author = div.xpath(".//h2/text()" ).get().strip()             href = div.xpath('./a/@href' ).get()              url = urljoin(self.start_urls[0 ],href)              content = div.xpath(".//div[@class='content']//text()" ).extract()             content = '' .join(content).strip()             item = QsbkItem(author=author, content=content)             i += 1              print('生成器调用:' ,i)             yield  item                                   next_path = response.xpath("//ul[@class='pagination']/li[last()]/a/@href" ).get()          if  not  next_path:              return          else :             next_url = urljoin(self.start_urls[0 ], next_path)             yield  scrapy.Request(next_url, callback=self.parse)