Scrapy爬取天气网站历史数据

基础部分

1.创建Scrapy项目

命令行界面 **scrapy startproject 项目名称**就会在当前目录下创建该爬虫项目

2.创建爬虫项目

通过**cd 项目名称进入项目后
使用
scrapy genspider 爬虫项目名称 网站域名(后期可改)**命令创建该爬虫(一个项目可以创建多个爬虫)

3.运行爬虫

1.命令行界面**scrapy crawl 爬虫项目名称**
2.在该项目下创建.py文件,这样每次运行爬虫只需要运行此脚本即可(文件内容)

from scrapy import cmdline
# 方式一:使用split()方法将字符串分隔成 方式二( (可选)--nolog:设置为无日志输出)
cmdline.execute("scrapy crawl 爬虫项目名称 --nolog".split())
# 方式二:注意execute的参数类型为一个列表
cmdline.execute(["scrapy","crawl","爬虫项目名称"])

4.爬虫各部分作用浅谈

image.png



项目

爬虫项目

# -*- coding: utf-8 -*-

import scrapy
from scrapy.selector import Selector
from MySpider.items import TianqiListItem # items中的类名
import  time
import random
import json
import copy
import pymysql
import pymysql.cursors

class TianqiSpider(scrapy.Spider):
    name = "TianqiSpider"
    allowed_domains = ["tianqi.com"]
    
    # 传入初始网页,多个网址可以使用列表加循环实现
    def start_requests(self):
        url = "https://lishi.tianqi.com/"
        yield scrapy.Request(url, callback=self.parse1)

	# 此部分需另外调用
    def create_mysql(self):
        """在数据库中创建表"""
        # 填写数据库用户名、数据库名、数据库用户密码、数据库url
        connect = pymysql.connect(user='root', db='weather_db', passwd='123456',
                                       host='127.0.0.1', charset="utf8", use_unicode=True)
        # 获取游标
        cursor = connect.cursor()
        # 通过如果表存在则删除
        # self.cursor.execute("DROP TABLE IF EXISTS data_table")
        # 创建表
        cursor.execute("CREATE TABLE weather_data (地名 CHAR(20),年月 CHAR(20),时间 CHAR(20),最高温度 int,最低温度 int,天气 CHAR(20),风向 CHAR(20),风速 CHAR(20),风向风速 CHAR(20),补充信息 CHAR(50),地方网址 CHAR(200),月份网址 CHAR(200),当天网址 CHAR(200))")
        cursor.close()
        # time.sleep(10)


    def parse4(self, response):
        """调用本地文件中的内容数据"""
        data_item = TianqiListItem()
        dataJson = json.load(open("C:/Users/Yin/Desktop/Program/数据/data_table.json", "r", encoding='UTF-8'))
        for each in dataJson:
            data_item['url1'] = each["地方网址"]
            data_item['data1'] = each["地名"]
            data_item['url2'] = each["月份网址"]
            data_item['data2'] = each["年月"]
            # 随机休眠躲避反爬
            time.sleep(random.uniform(1, 3))
            yield scrapy.Request(url=each["url2"], meta={'data_item':copy.deepcopy(data_item)},
                                 callback=self.parse3,
                                 dont_filter=True, )

    # 地区
    def parse1(self, response):
        data_item = TianqiListItem()
        sel = Selector(response)
        web1 = sel.xpath('//*[@class="tablebox"]/table/tbody/tr/td/ul/li')
        for each2 in web1:
            try:
                url1 = "https://lishi.tianqi.com/" + each2.xpath('.//a/@href').extract()[0] # 地方网址
                data1 = each2.xpath('.//a/text()').extract()[0] # 地名
                data_item['url1'] = url1
                data_item['data1'] = data1

                # 随机休眠躲避反爬
                time.sleep(random.uniform(1, 3))
                #使用copy.deepcopy(data_item)传递数据,避免后期数据错乱[因为使用 Request 函数传递 item 时,使用的是浅复制(对象的字段值被复制时,字段引用的对象不会被复制)]
                yield scrapy.Request(url=url1, meta={'data_item': copy.deepcopy(data_item)},
                                    callback=self.parse2,
                                    dont_filter=True, )
            except:
                pass

    # 年份
    def parse2(self, response):
        data_item = response.meta['data_item']
        sel = Selector(response)
        web1 = sel.xpath('//*[@class="main clearfix"]/div[1]/div[11]/div/div/ul/li')
        for each3 in web1:
            url2 = each3.xpath('.//a/@href').extract()[0] # 月份网址
            print(url2)
            data2 = each3.xpath('.//a/text()').extract()[0] # 年月
            data_item['url2'] = url2
            data_item['data2'] = data2

            # 随机休眠躲避反爬
            time.sleep(random.uniform(2, 4))
            yield scrapy.Request(url=url2, meta={'data_item': copy.deepcopy(data_item)},
                                 callback=self.parse3,
                                 dont_filter=True, )

    # 月份
    def parse3(self, response):
        data_item = response.meta['data_item']
        sel = Selector(response)
        web1 = sel.xpath('//*[@class="main clearfix"]/div[1]/div[5]/div/div[2]/ul[2]/li')
        # 查看过程中发现网页有新旧2种模板
        if web1:
            for each in web1:
                url3 = each.xpath('.//div/a/@href').extract()  # 当天网址
                data3 = each.xpath('.//div/a/text()').extract()  # 时间
                data4 = each.xpath('.//div[2]/text()').extract()  # 最高温度
                data5 = each.xpath('.//div[3]/text()').extract()  # 最低温度
                data6 = each.xpath('.//div[4]/text()').extract()  # 天气
                try:
                    data_ = each.xpath('.//div[5]/text()').extract()[0].split()
                    data7 = data_[0]  # 风向
                    data8 = data_[1]  # 风速
                except:
                    pass
                try:
                    # 补充数据
                    data9 = sel.xpath('//div[5]/div[@class="linegraphbox"]/div[1]/text()').extract()[0].replace('\r','\t', '')
                    data_item['data9'] = data9
                except:
                    data_item['data9'] = None
                try:
                    data10 = sel.xpath('//div[5]/div[@class="linegraphbox"]/div[1]/text()').extract()[0].replace('\r','').replace('\n', '').replace('\t', '')
                    data_item['data10'] = data10
                except:
                    data_item['data10'] = None
                try:
                    data_item['url3'] = "https:" + url3[0]
                except:
                    data_item['url3'] = None
                try:
                    data_item['data3'] = data3[0]
                except:
                    data_item['data3'] = None
                try:
                    data_item['data4'] = data4[0]
                except:
                    data_item['data4'] = None
                try:
                    data_item['data5'] = data5[0]
                except:
                    data_item['data5'] = None
                try:
                    data_item['data6'] = data6[0]
                except:
                    data_item['data6'] = None
                try:
                    data_item['data7'] = data7
                    data_item['data8'] = data8
                except:
                    data_item['data7'] = None
                    data_item['data8'] = None

                # yield出去之后,这个Item就会进入到pipelines里面去
                print(data_item)
                yield data_item
        else:
            # 第二种网页模板
            web2 = sel.xpath('//div[@class="tian_three"]/ul[@class="thrui"]/li')
            try:
                data10 = sel.xpath('//div[1]/div[@class="linegraphborder"]/div/div[@class="linegraphtitle"]/text()').extract()[0].replace('\r','').replace('\n', '').replace('\t', '')
            except:
                pass

            for each in web2:
                data3 = each.xpath('.//div[1]/text()').extract()  # 时间
                data4 = each.xpath('.//div[2]/text()').extract()  # 最高温度
                data5 = each.xpath('.//div[3]/text()').extract()  # 最低温度
                data6 = each.xpath('.//div[4]/text()').extract()  # 天气
                try:
                    data_ = each.xpath('.//div[5]/text()').extract()[0].split()
                    data7 = data_[0]  # 风向
                    data8 = data_[1]  # 风速
                    if data7 == data8:
                        data7,data8=None,None
                        data9 = data_[0]
                except:
                    pass
                try:
                    data_item['url3'] = None
                except:
                    data_item['url3'] = None
                try:
                    data3 = data3[0].split()
                    data_item['data3'] = data3[0]
                except:
                    data_item['data3'] = None
                try:
                    data_item['data4'] = data4[0].replace("℃", "")
                except:
                    data_item['data4'] = None
                try:
                    data_item['data5'] = data5[0].replace("℃", "")
                except:
                    data_item['data5'] = None
                try:
                    data_item['data6'] = data6[0]
                except:
                    data_item['data6'] = None
                try:
                    data_item['data7'] = data7
                    data_item['data8'] = data8
                except:
                    data_item['data7'] = None
                    data_item['data8'] = None
                try:
                    data_item['data9'] = data9
                except:
                    data_item['data9'] = None
                try:
                    data_item['data10'] = data10
                except:
                    data_item['data10'] = None
                yield data_item


items部分

# 天气网(新建一个类,类名在爬虫文件中用到)
class TianqiListItem(scrapy.Item):
    data1= scrapy.Field() # 地名
    data2= scrapy.Field() # 年月
    data3= scrapy.Field() # 时间
    data4= scrapy.Field() # 最高温度
    data5= scrapy.Field() # 最低温度
    data6= scrapy.Field() # 天气
    data7= scrapy.Field() # 风向
    data8= scrapy.Field() # 风速
    data9= scrapy.Field() # 风向风速
    data10= scrapy.Field()# 补充信息
    data11= scrapy.Field()
    url1= scrapy.Field() # 地方网址
    url2 = scrapy.Field() # 月份网址
    url3 = scrapy.Field() # 当天网址


middlware部分

随机生成更换user-agent的类

from fake_useragent import UserAgent

class RandomUserAgentMiddlware(object):
    """随机更换user-agent
    """
    def __init__(self,crawler):
        super(RandomUserAgentMiddlware,self).__init__()
        self.ua = UserAgent() # 函数实例
    # @classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。
    @classmethod
    def from_crawler(cls,crawler):
        return cls(crawler)

    def process_request(self,request,spider):
        request.headers.setdefault("User-Agent",self.ua.random,) # 调用函数,生成随机用户代理


pipelines部分

数据存入Mysql:

import pymysql
import pymysql.cursors

class MyspiderMysqlPipeline(object):
    """
    提交数据到mysql
    """
    def __init__(self):
        # 分别填写 数据库用户名、数据库用户密码、数据库名、数据库地址(127.0.0.1表示本地数据库)、指定编码格式(防止乱码)、是否指定字符的编码/解码格式
        self.connect = pymysql.connect(user='root', passwd='123456',db='weather_db', 
                                    host='127.0.0.1',charset="utf8", use_unicode=True)
        # 获取游标(分别后面使用游标操作数据库)
        self.cursor = self.connect.cursor()
        try:
        #     # 删除原有的表
        #     self.cursor.execute("DROP TABLE IF EXISTS data_table")
        #使用SQL语句创建表
            self.cursor.execute("CREATE TABLE data_table(地名 CHAR(20),年月 CHAR(20),时间 CHAR(20),最高温度 int,最低温度 int,天气 CHAR(20),风向 CHAR(20),风速 CHAR(20),风向风速 CHAR(20),补充信息 CHAR(50),地方网址 CHAR(200),月份网址 CHAR(200),当天网址 CHAR(200))")
        except:
            print("表已存在")
        #关闭游标
        # self.cursor.close()

    def process_item(self, item, spider):
        """数据入库"""
        try:
            #使用if语句对传入的数据判断是来自哪个爬虫项目,已进行区分存储
            if spider.name == "TianqiSpider":
                # 设置插入格式
                sql_text = 'insert into data_table(地名,年月,时间,最高温度,最低温度,天气,风向,风速,风向风速,补充信息,地方网址,月份网址,当天网址)values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
                # 执行SQL语句,传入数据(item为 items文件中所设置的数据格式)
                self.cursor.execute(sql_text, (item["data1"],item["data2"],item["data3"],item["data4"],item["data5"],item["data6"],item["data7"],item["data8"],item["data9"],item["data10"],item["url1"],item["url2"],item["url3"]))
                # 提交,不进行提交无法保存到数据库
                self.connect.commit()
            return item
        except:
            pass

数据储存为Json格式

from  scrapy.exporters import JsonItemExporter

class MyspiderJsonPipeline(object):
    """
    数据以Json格式保存
    """
    def __init__(self):
        self.file = open("Weather_data.json","wb") # 生成json文件,并设置操作模式
        self.exporter = JsonItemExporter(self.file,encoding="utf-8",ensure_ascii=False)
        self.exporter.start_exporting()

    def close_spider(self,spider):
        self.exporter.finish_exporting()
        self.file.close()

    def process_item(self,item,spider):
        self.exporter.export_item(item)
        return  item


settings部分

# 是否遵守爬虫规则
ROBOTSTXT_OBEY = False

# 是否激活cookie,即是否使用scrapy自带的cookie
COOKIES_ENABLED = False

# 用于限制爬行速度
DOWNLOAD_DELAY = 1 # 1000 ms of delay

# 设置线程数量(默认16)
CONCURRENT_REQUESTS = 16

# 添加中间件
DOWNLOADER_MIDDLEWARES = {
    'MySpider.middlewares.RandomUserAgentMiddlware' : 400,
}

# 管道文件即文件保存
ITEM_PIPELINES = {
   'MySpider.pipelines.MyspiderMysqlPipeline': 300,
   'MySpider.pipelines.MyspiderJsonPipeline': 301,
}

收集:
Scrapy设置cookie遇到的坑

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值