Python爬蟲 --- 2.4 Scrapy之天氣預報爬蟲實踐

原文鏈接:https://www.fkomm.cn/article/2018/8/5/31.html

目的

寫一個真正意義上一個爬蟲,並將他爬取到的數據分別保存到txt、json、已經存在的mysql數據庫中。

目標分析:

這次我們要爬的是 中國天氣網:http://www.weather.com.cn/
隨便點開一個城市的天氣比如合肥: http://www.weather.com.cn/weather/101220101.shtml
我們要爬取的就是圖中的:合肥七天的前期預報:

Python爬蟲 --- 2.4 Scrapy之天氣預報爬蟲實踐

數據的篩選:

我們使用chrome開發者工具,模擬鼠標定位到相對應位置:

Python爬蟲 --- 2.4 Scrapy之天氣預報爬蟲實踐

可以看到我們需要的數據,全都包裹在

<ul class="t clearfix">

裏。 我們用bs4、xpath、css之類的選擇器定位到這裏,再篩選數據就行。 本着學習新知識的原則,文中的代碼將會使用xpath定位。 這裏我們可以這樣:

response.xpath('//ul[@class="t clearfix"]')

Scrapy 框架的實施:

創建scrapy項目和爬蟲:

    $ scrapy startproject weather
     $ cd weather
     $ scrapy genspider HFtianqi www.weather.com.cn/weather/101220101.shtml

這樣我們就已經將準備工作做完了。 看一下當前的目錄:

``` .
├── scrapy.cfg
└── weather
├── init.py
├── pycache
│ ├── init.cpython-36.pyc
│ └── settings.cpython-36.pyc
├── items.py
├── middlewares.py
├── pipelines.py
├── settings.py
└── spiders
├── HFtianqi.py
├── init.py
└── pycache
└── init.cpython-36.pyc

 4 directories, 11 files

### 編寫items.py:

這次我們來先編寫items,十分的簡單,只需要將希望獲取的字段名填寫進去:
import scrapy

 class WeatherItem(scrapy.Item):
     # define the fields for your item here like:
     # name = scrapy.Field()
     date = scrapy.Field()
     temperature = scrapy.Field()
     weather = scrapy.Field()
     wind = scrapy.Field()

### 編寫Spider:

**這個部分使我們整個爬蟲的核心!!**

主要目的是:

> 將Downloader發給我們的Response裏篩選數據,並返回給PIPELINE處理。

下面我們來看一下代碼:
# -*- coding: utf-8 -*-
 import scrapy

 from weather.items import WeatherItem

 class HftianqiSpider(scrapy.Spider):
     name = 'HFtianqi'
     allowed_domains = ['www.weather.com.cn/weather/101220101.shtml']
     start_urls = ['http://www.weather.com.cn/weather/101220101.shtml']

     def parse(self, response):
         '''
         篩選信息的函數:
         date = 日期
         temperature = 當天的溫度
         weather = 當天的天氣
         wind = 當天的風向
         '''

         # 先建立一個列表,用來保存每天的信息
         items = []

         # 找到包裹着天氣信息的div
         day = response.xpath('//ul[@class="t clearfix"]')

         # 循環篩選出每天的信息:
         for i  in list(range(7)):
             # 先申請一個weatheritem 的類型來保存結果
             item = WeatherItem()

             # 觀察網頁,並找到需要的數據
             item['date'] = day.xpath('./li['+ str(i+1) + ']/h1//text()').extract()[0]

             item['temperature'] = day.xpath('./li['+ str(i+1) + ']/p[@class="tem"]/i/text()').extract()[0]

             item['weather'] = day.xpath('./li['+ str(i+1) + ']/p[@class="wea"]/text()').extract()[0]

             item['wind'] = day.xpath('./li['+ str(i+1) + ']/p[@class="win"]/em/span/@title').extract()[0] + day.xpath('./li['+ str(i+1) + ']/p[@class="win"]/i/text()').extract()[0]

             items.append(item)

         return items

### 編寫PIPELINE:

我們知道,pipelines.py是用來處理收尾爬蟲抓到的數據的, 一般情況下,我們會將數據存到本地:

- 文本形式: 最基本的存儲方式
- json格式 :方便調用
- 數據庫: 數據量比較大時選擇的存儲方式

**TXT(文本)格式:**
    import os
    import requests
    import json
    import codecs
    import pymysql

    class WeatherPipeline(object):
      def process_item(self, item, spider):

          print(item)
          # print(item)
          # 獲取當前工作目錄
          base_dir = os.getcwd()
          # 文件存在data目錄下的weather.txt文件內,data目錄和txt文件需要自己事先建立好
          filename = base_dir + '/data/weather.txt'

          # 從內存以追加的方式打開文件,並寫入對應的數據
          with open(filename, 'a') as f:
              f.write(item['date'] + '\n')
              f.write(item['temperature'] + '\n')
              f.write(item['weather'] + '\n')
              f.write(item['wind'] + '\n\n')

          return item

**json格式數據:**

我們想要輸出json格式的數據,最方便的是在PIPELINE裏自定義一個class:
    class W2json(object):
      def process_item(self, item, spider):
          '''
          講爬取的信息保存到json
          方便其他程序員調用
          '''
          base_dir = os.getcwd()
          filename = base_dir + '/data/weather.json'

          # 打開json文件,向裏面以dumps的方式吸入數據
          # 注意需要有一個參數ensure_ascii=False ,不然數據會直接爲utf編碼的方式存入比如:“/xe15”
          with codecs.open(filename, 'a') as f:
              line = json.dumps(dict(item), ensure_ascii=False) + '\n'
              f.write(line)

          return item

**數據庫格式(mysql):**

Python對市面上各種各樣的數據庫的操作都有良好的支持, 但是現在一般比較常用的免費數據庫mysql。

- 在本地安裝mysql:

linux和mac都有很強大的包管理軟件,如apt,brew等等,window 可以直接去官網下載安裝包。

*由於我是Mac,所以我是說Mac的安裝方式了。*

`$ brew install mysql`

在安裝的過程中,他會要求你填寫root用戶的密碼,這裏的root並不是系統層面上的超級用戶,是mysql數據庫的超級用戶。 安裝完成後mysql服務是默認啓動的, 如果重啓了電腦,需要這樣啓動(mac):

`$ mysql.server start`

- 登錄mysql並創建scrapy用的數據庫:

登錄進mysql

$ mysql -uroot -p

創建數據庫:ScrapyDB ,以utf8位編碼格式,每條語句以’;‘結尾

CREATE DATABASE ScrapyDB CHARACTER SET 'utf8';

選中剛纔創建的表:

use ScrapyDB;

創建我們需要的字段:字段要和我們代碼裏一一對應,方便我們一會寫sql語句

CREATE TABLE weather(
id INT AUTO_INCREMENT,
date char(24),
temperature char(24),
weather char(24),
wind char(24),
PRIMARY KEY(id) )ENGINE=InnoDB DEFAULT CHARSET='utf8'


來看一下weather表長啥樣:

show columns from weather
或者:desc weather


- 安裝Python的mysql模塊:

` pip install pymysql`

最後我們編輯一下代碼:

class W2mysql(object):
def process_item(self, item, spider):
'''
將爬取的信息保存到mysql
'''

      # 將item裏的數據拿出來
      date = item['date']
      temperature = item['temperature']
      weather = item['weather']
      wind = item['wind']

      # 和本地的scrapyDB數據庫建立連接
      connection = pymysql.connect(
          host='127.0.0.1',  # 連接的是本地數據庫
          user='root',        # 自己的mysql用戶名
          passwd='********',  # 自己的密碼
          db='ScrapyDB',      # 數據庫的名字
          charset='utf8mb4',     # 默認的編碼方式:
          cursorclass=pymysql.cursors.DictCursor)

      try:
          with connection.cursor() as cursor:
              # 創建更新值的sql語句
              sql = """INSERT INTO WEATHER(date,temperature,weather,wind)
                      VALUES (%s, %s, %s, %s)"""
              # 執行sql語句
              # excute 的第二個參數可以將sql缺省語句補全,一般以元組的格式
              cursor.execute(
                  sql, (date, temperature, weather, wind))

          # 提交本次插入的記錄
          connection.commit()
      finally:
          # 關閉連接
          connection.close()

return item


### 編寫Settings.py

我們需要在Settings.py將我們寫好的PIPELINE添加進去, scrapy才能夠跑起來。

這裏只需要增加一個dict格式的ITEM_PIPELINES, 數字value可以自定義,數字越小的優先處理。
BOT_NAME = 'weather'

 SPIDER_MODULES = ['weather.spiders']
 NEWSPIDER_MODULE = 'weather.spiders'

 ROBOTSTXT_OBEY = True

 ITEM_PIPELINES = {
    'weather.pipelines.WeatherPipeline': 300,
    'weather.pipelines.W2json': 400,
    'weather.pipelines.W2mysql': 300,
 }

### 讓項目跑起來:

 `$ scrapy crawl HFtianqi`

## 結果展示:

文本格式:
![](https://s1.51cto.com/images/blog/201812/19/430fad83258242b0837f9c7ba1195430.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

json格式:
![](https://s1.51cto.com/images/blog/201812/19/d9d06172f9b30eac709b03a63d773017.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

數據庫格式:
![](https://s1.51cto.com/images/blog/201812/19/4e0a8915c3bfd10788338ec0bf6f7ae4.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

這次的例子就到這裏了,主要介紹如何通過自定義PIPELINE來將爬取的數據以不同的方式保存。

        
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章