Scrapy教程——搭建環境、創建項目、爬取內容、保存文件
1、創建項目
在開始爬取之前,您必須創建一個新的Scrapy項目。進入您打算存儲代碼的目錄中,運行新建命令。
例如,我需要在D:\00Coding\Python\scrapy目錄下存放該項目,打開命令窗口,進入該目錄,執行以下命令:
scrapy startproject tutorial
PS:tutorial可以替換成任何你喜歡的名稱,最好是英文
該命令將會創建包含下列內容的 tutorial 目錄:
tutorial/ scrapy.cfg tutorial/ __init__.py items.py pipelines.py settings.py spiders/ __init__.py ...
這些文件分別是:
scrapy.cfg: 項目的配置文件
tutorial/: 該項目的python模塊。之後您將在此加入代碼。
tutorial/items.py: 項目中的item文件.
tutorial/pipelines.py: 項目中的pipelines文件.
tutorial/settings.py: 項目的設置文件.
tutorial/spiders/: 放置spider代碼的目錄.
2、定義Item
Item 是保存爬取到的數據的容器;其使用方法和python字典類似,並且提供了額外保護機制來避免拼寫錯誤導致的未定義字段錯誤。我們需要從想要爬取的網站(這裏爬取新浪新聞)中獲取以下屬性:
新聞大類url、新聞大類title;
新聞小類url、新聞小類title;
新聞url、新聞title;
新聞標題、新聞內容;
對此,在item中定義相應的字段。編輯tutorial目錄中的 items.py 文件:
[python] view plain copy
- from scrapy.item import Item, Field
- class TutorialItem(Item):
- # define the fields for your item here like:
- # name = scrapy.Field()
- parent_title = Field()
- parent_url = Field()
- second_title = Field()
- second_url = Field()
- path = Field()
- link_title = Field()
- link_url = Field()
- head= Field()
- content = Field()
- pass
3、編寫爬蟲(Spider)
Spider是用戶編寫用於從單個網站(或者一些網站)爬取數據的類。
1、sinaSpider.py文件:
包含了一個用於下載的初始URL,如何跟進網頁中的鏈接以及如何分析頁面中的內容,提取生成 item 的方法。為了創建一個Spider,您必須繼承 scrapy.Spider 類,且定義以下三個屬性:
name:用於區別Spider。該名字必須是唯一的,您不可以為不同的Spider設定相同的名字。
start_urls:包含了Spider在啟動時進行爬取的url列表。因此,第一個被獲取到的頁面將是其中之一。後續的URL則從初始的URL獲取到的數據中提取。
parse() 是spider的一個方法。被調用時,每個初始URL完成下載後生成的Response 對象將會作為唯一的參數傳遞給該函數。該方法負責解析返回的數據(response data),提取數據(生成item)以及生成需要進一步處理的URL的Request 對象。
當我們爬取了大類,然後這時候沒有保存item,而是傳遞item到小類,爬取完小類之後,我們需要去新聞詳情頁爬取新聞的內容和標題:
主要思路是:paser->second_paser->detail_parse
以下是sinaSpider的全部代碼:
[python] view plain copy
- # -*-coding: utf-8 -*-
- __author__= ‘George‘
- import sys, os
- reload(sys)
- sys.setdefaultencoding("utf-8")
- from scrapy.spider import Spider
- from scrapy.http import Request
- from scrapy.selector import Selector
- from tutorial.items import TutorialItem
- base ="d:/dataset/" #存放文件分類的目錄
- class SinaSpider(Spider):
- name= "sina"
- allowed_domains= ["sina.com.cn"]
- start_urls= [
- "http://news.sina.com.cn/guide/"
- ]#起始urls列表
- def parse(self, response):
- items= []
- sel= Selector(response)
- big_urls=sel.xpath(‘//div[@id=\"tab01\"]/div/h3/a/@href‘).extract()#大類的url
- big_titles=sel.xpath("//div[@id=\"tab01\"]/div/h3/a/text()").extract()
- second_urls =sel.xpath(‘//div[@id=\"tab01\"]/div/ul/li/a/@href‘).extract()#小類的url
- second_titles=sel.xpath(‘//div[@id=\"tab01\"]/div/ul/li/a/text()‘).extract()
- for i in range(1,len(big_titles)-1):#這裏不想要第一大類,big_title減去1是因為最後一個大類,沒有跳轉按鈕,也去除
- file_name = base + big_titles[i]
- #創建目錄
- if(not os.path.exists(file_name)):
- os.makedirs(file_name)
- for j in range(19,len(second_urls)):
- item = TutorialItem()
- item[‘parent_title‘] =big_titles[i]
- item[‘parent_url‘] =big_urls[i]
- if_belong =second_urls[j].startswith( item[‘parent_url‘])
- if(if_belong):
- second_file_name =file_name + ‘/‘+ second_titles[j]
- if(not os.path.exists(second_file_name)):
- os.makedirs(second_file_name)
- item[‘second_url‘] = second_urls[j]
- item[‘second_title‘] =second_titles[j]
- item[‘path‘] =second_file_name
- items.append(item)
- for item in items:
- yield Request(url=item[‘second_url‘],meta={‘item_1‘: item},callback=self.second_parse)
- #對於返回的小類的url,再進行遞歸請求
- def second_parse(self, response):
- sel= Selector(response)
- item_1= response.meta[‘item_1‘]
- items= []
- bigUrls= sel.xpath(‘//a/@href‘).extract()
- for i in range(0, len(bigUrls)):
- if_belong =bigUrls[i].endswith(‘.shtml‘) and bigUrls[i].startswith(item_1[‘parent_url‘])
- if(if_belong):
- item = TutorialItem()
- item[‘parent_title‘] =item_1[‘parent_title‘]
- item[‘parent_url‘] =item_1[‘parent_url‘]
- item[‘second_url‘] =item_1[‘second_url‘]
- item[‘second_title‘] =item_1[‘second_title‘]
- item[‘path‘] = item_1[‘path‘]
- item[‘link_url‘] = bigUrls[i]
- items.append(item)
- for item in items:
- yield Request(url=item[‘link_url‘], meta={‘item_2‘:item},callback=self.detail_parse)
- def detail_parse(self, response):
- sel= Selector(response)
- item= response.meta[‘item_2‘]
- content= ""
- head=sel.xpath(‘//h1[@id=\"artibodyTitle\"]/text()‘).extract()
- content_list=sel.xpath(‘//div[@id=\"artibody\"]/p/text()‘).extract()
- for content_one in content_list:
- content += content_one
- item[‘head‘]= head
- item[‘content‘]= content
- yield item
2、pipelines.py
主要是對於抓取數據的保存(txt),這裏把文件名命名為鏈接中‘/‘替換成‘_‘
[python] view plain copy
- # -*- coding: utf-8 -*-
- # Define your item pipelines here
- #
- # Don‘t forget to add your pipeline to the ITEM_PIPELINES setting
- # See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
- from scrapy import signals
- import json
- import codecs
- import sys
- reload(sys)
- sys.setdefaultencoding( "utf-8" )
- class SinaPipeline(object):
- def process_item(self, item, spider):
- link_url = item[‘link_url‘]
- file_name = link_url[7:-6].replace(‘/‘,‘_‘)
- file_name += ".txt"
- fp = open(item[‘path‘]+‘/‘+file_name, ‘w‘)
- fp.write(item[‘content‘])
- fp.close()
- return item
3、setting.py
這是設置文件,這裏需要設置同時開啟的線程數目、日誌打印的級別等
[python] view plain copy
- # -*- coding: utf-8 -*-
- BOT_NAME = ‘tutorial‘
- SPIDER_MODULES = [‘tutorial.spiders‘]
- NEWSPIDER_MODULE = ‘tutorial.spiders‘
- ITEM_PIPELINES = {
- ‘tutorial.pipelines.SinaPipeline‘: 300,
- }
- LOG_LEVEL = ‘INFO‘
- ROBOTSTXT_OBEY = True
爬取結果
這裏的文件夾是根據分類,然後創建的;
這是大類的文件夾,現在我們已經將item都爬下來了,就需要存了,這裏只想要存內容,所以直接將item裏面的content字段的內容寫入txt。
這裏通過將鏈接進行處理,轉換成文件名,最後保存到所屬的那個類裏;
Scrapy教程——搭建環境、創建項目、爬取內容、保存文件