scrapy專案總結——爬取汙染資料的專案
阿新 • • 發佈:2018-12-10
經過一段時間的學習,開始慢慢學會了使用scray簡單的爬取資料。 這個專案起源是對汙染資料的需求。 起初找到一個網站,嘗試對其進行爬取,但是網站涉及到動態載入的問題,目前本人只學會了靜態網站的爬取,所以放棄了。等後期學習後會返回進行嘗試。網址為:
https://www.aqistudy.cn/historydata/
本專案實際使用的資源為:
http://www.tianqihoubao.com/aqi/
首先進行專案建立;
scrapy startproject Aqi
在建立好的scrapy容器裡面建立一個spider:WRS,中間程式碼片如下:
import scrapy
from Aqi.items import AqiItem
class AQISpider(scrapy.Spider):
name = 'WRS'
start_urls = ['http://www.tianqihoubao.com/aqi/']
#這裡必須為start_urls,兩次專案都在這個s處尋找半天debug
# allowed_domains = ['tianqihoubao.com']
def parse(self, response):
for url in response.xpath('//*[@id="content"]/div/dl/dd/a/@href' ).extract()[9:]:
full_url = response.urljoin(url)
yield scrapy.Request(full_url, callback=self.parse_city)
def parse_city(self, response):
for url in response.xpath('//*[@id="bd"]/div[1]/div[3]/ul/li/a/@href').extract():
try:
full_url = response.urljoin(url)
finally :
yield scrapy.Request(full_url, callback=self.parse_month)
def parse_month(self, response):
#這裡是一個對爬取到的資料的處理(求平均值),進行過3次嘗試。還是基礎知識不太紮實
def avera(ur):
av = 0
for i in ur:
av = av + float(i)
aver = av / len(ur)
return aver
item = AqiItem()
item['city'] = response.xpath('//*[@id="bd"]/div[2]/div[4]/h2/text()').extract()
#因為chrome瀏覽器的原因,造成網頁原始碼裡不含tbody;但是審查元素時瀏覽器會自動加上tbody,故直接刪除tvbody即可
item['AQI'] = avera(response.xpath('//*[@id="content"]/div[3]/table/tr/td[3]/text()').extract()[1:])
item['PM25'] = avera(response.xpath('//*[@id="content"]/div[3]/table/tr/td[5]/text()').extract()[1:])
item['PM10'] = avera(response.xpath('//*[@id="content"]/div[3]/table/tr/td[6]/text()').extract()[1:])
item['So2'] = avera(response.xpath('//*[@id="content"]/div[3]/table/tr/td[7]/text()').extract()[1:])
item['No2'] = avera(response.xpath('//*[@id="content"]/div[3]/table/tr/td[8]/text()').extract()[1:])
item['Co'] = avera(response.xpath('//*[@id="content"]/div[3]/table/tr/td[9]/text()').extract()[1:])
item['O3'] = avera(response.xpath('//*[@id="content"]/div[3]/table/tr/td[10]/text()').extract()[1:])
yield item
#for aA in response.xpath('//*[@id="content"]/div[3]/table/tr/td[1]/text()').extract():
#AQI =
#for i in range(1, (1+len(response.xpath('//*[@id="content"]/div[3]/table/tr/td[1]/text()').extract()))):
#item = AqiItem()
#item['city'] = response.xpath('//*[@id="content"]/div[3]/h4/text()').extract()
#item['time'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[1]/text()').extract()[i]
#item['AQI'] = float(response.xpath('//*[@id="content"]/div[3]/table/tr/td[3]/text()').extract()[i])
#item['PM25'] = float(response.xpath('//*[@id="content"]/div[3]/table/tr/td[5]/text()').extract()[i])
#item['PM10'] = float(response.xpath('//*[@id="content"]/div[3]/table/tr/td[6]/text()').extract()[i])
# item['So2'] = float(response.xpath('//*[@id="content"]/div[3]/table/tr/td[7]/text()').extract()[i])
# item['No2'] = float(response.xpath('//*[@id="content"]/div[3]/table/tr/td[8]/text()').extract()[i])
# item['Co'] = float(response.xpath('//*[@id="content"]/div[3]/table/tr/td[9]/text()').extract()[i])
# item['O3'] = float(response.xpath('//*[@id="content"]/div[3]/table/tr/td[10]/text()').extract()[i])
# finally:
# yield item
#item = AqiItem()
#item['city'] = response.xpath('//*[@id="content"]/h1/text()').extract()
#item['time'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[1]/text()').extract()[1:]
#item['AQI'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[3]/text()').extract()[1:]
#item['PM25'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[5]/text()').extract()[1:]
#item['PM10'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[6]/text()').extract()[1:]
#item['So2'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[7]/text()').extract()[1:]
#item['No2'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[8]/text()').extract()[1:]
#item['Co'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[9]/text()').extract()[1:]
#item['O3'] = response.xpath('//*[@id="content"]/div[3]/table/tr/td[10]/text()').extract()[1:]
#yield item
在spider裡面,主要問題就是兩個問題:
- start_urls
- 對基礎不太熟悉,導致浪費時間在處理上
- 目前兩個專案都存在的一個問題:每次爬取到的資料第一個列表都不需要,兩次都是使用不同的方法去除第一個列表,所以需要總結一個固定的方法丟擲第一個資料 在items.py裡面建立需要返回的item:
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class AqiItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
city = scrapy.Field()
# time = scrapy.Field()
AQI = scrapy.Field()
PM25 = scrapy.Field()
PM10 = scrapy.Field()
So2 = scrapy.Field()
No2 = scrapy.Field()
Co = scrapy.Field()
O3 = scrapy.Field()
pass
對應item,新建一個PipeLine對返回的資料進行操作:
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import time
class AqiFilePipeLine(object):
def __init__(self):
self.file = open('d:/Aqi/wuqueshi.txt', 'wb')
def process_item(self, item, spider):
line = "%s,%s,%s,%s,%s,%s,%s,%s\r\n" % (item['city'], item['AQI'], item['PM25'],
item['PM10'], item['So2'], item['No2'], item['Co'], item['O3'])
self.file.write(line.encode("utf-8"))
#fp.write(item['city'] + '\t')
#fp.write(item['time'] + '\t')
#fp.write(item['AQI'] + '\t')
#fp.write(item['PM25'] + '\t')
#fp.write(item['PM10'] + '\t')
#fp.write(item['So2'] + '\t')
#fp.write(item['No2'] + '\t')
#fp.write(item['Co'] + '\t')
#fp.write(item['O3'] + '\n\n')
time.sleep(0.2)
return item
在匯出資料這裡,進行過多次嘗試,每次得到的資料格式都不太滿意。因為最初沒有算出平均值,而是直接得出所需要的日資料,而每一個原始資料都存在\r\n;所以都會有大量空格存在。處理方法為:將得到的數字資料轉化為float格式,城市資料來源改變,日期資料刪除。但是沒有解決這個問難。希望後續可以補上。 這裡若是不設定time.sleep。則得到的資料可能會相應減少,因為訪問網站的頻率過快。 對應的PipeLine,設定相應的Setting,其中的AUTOTHROTTLE_ENABLED 應該去除註釋,可以得到更完整的資料:
AUTOTHROTTLE_ENABLED = True
。本專案的缺點在於:
- 遇到動態載入的網站沒有找到爬取的方法
- start_urls問題為老問題
- 爬取資料的第一行仍然沒有固定的方法排除
- 得到的結果因為不明原因會有缺失,並且得到的資料格式與網頁資料不符