scrapy框架 对全站信息的爬取(以爬取全站天气信息为例)
思路:
scrapy爬取整个网站的流程(以爬取所有省份的所有城市的所有年份的所有季度的所有月份的每一天为例)
在scarpy的类中,定义一个开始的url
通过第一个函数和url来获取每一个省份的所有城市的url链接,对于每一个url链接,通过yield方法和callback函数来调用第二个函数并且通过yield方法传入各个城市的url信息
在第二个函数中,通过bs4或者xpath或者正则表达式来实现对每个城市每年的每个季度的每个月份得到url信息的获取,通过callback调用第三个函数和yield方法给第三个函数传入url信息
在第三个函数中,通过bs4或者xpath或者正则表达式来实现对每个城市每年每月每日的天气的信息的获取
至此,实现了通过scrapy库对全站信息的爬取
具体代码实现:
# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
from scrapy import Request
from lxml import etree
from Weather.items import WeatherItem
class WeatherSpider(scrapy.Spider):
name = 'dmoz' # 爬虫的名字
# 允许爬虫的网站容器
# allowed_domains = ['tianqihoubao']
start_urls = ['http://www.tianqihoubao.com/lishi/']
# 解析http://www.tianqihoubao.com/lishi/网页,获取每个省中的每个城市的信息的url
def parse(self, response):
soup = BeautifulSoup(response.text, 'lxml')
citylists = soup.find_all(name='div', class_='citychk')
# 获取到了省份的城市列表
for citys in citylists:
# 获取每个省份中的每个城市列表
for city in citys.find_all(name='dd'):
# 通过每个省中的每个城市信息来组成每一个城市的url信息
url = 'http://www.tianqihoubao.com' + city.a['href']
# 返回Request对象,作为新的url由框架进行调度请求,返回的response有回调函数parse_citylist进行解析
yield Request(url=url,callback=self.parse_citylist)
# 例如解析http://www.tianqihoubao.com/lishi/beijing.html,获取到每一个城市每一年具体到每一个月的天气的url
def parse_citylist(self, response):
soup = BeautifulSoup(response.text, 'lxml')
# 可以获取2011年到2019年的全部信息,这里是获取一年的天气信息
monthlist = soup.find_all(name='div', class_='wdetail')
for months in monthlist:
# 遍历每一个li标签下的月份信息
for month in months.find_all(name='li'):
if month.text.endswith("季度:"):
continue
else:
url = month.a['href']
url = 'http://www.tianqihoubao.com' + url
# 返回Request对象,作为新的url由框架进行调度请求,返回的response由parse_weather进行解析
yield Request(url=url,callback=self.parse_weather)
# 通过每一个月的url,来获取到每一天的天气信息
def parse_weather(self, response):
url = response.url
# 获取城市名称
cityname = url.split('/')[4]
weather_html = etree.HTML(response.text)
# 每一条详细信息的集合
table = weather_html.xpath('//table//tr//td//text()')
listall = []
# 获取每一条的详细内容
for t in table:
# 如果标签内没有信息的话
if t.strip() == '':
continue
# 替换元素中的空格和\r\n
t1 = t.replace(' ', '')
t2 = t1.replace('\r\n', '')
listall.append(t2.strip())
# 对提取到的列表数据进行拆分,将一个月的天气数据拆分成每天的天气情况
n = 4
# 这里相当于把元祖里面的元素四个重组成一个元素了
sublist = [listall[i:i + n] for i in range(0, len(listall), n)]
# 删除表头标题那一行,去除不需要的标题信息
sublist.remove(sublist[0])
# 将列表元素中的最高和最低气温拆分,方便后续数据分析,并插入城市代码 这里是对于每一个列表
for sub in sublist:
# sublist[0]中不存在任何信息
if sub == sublist[0]:
pass
# 可以切片,将温度分为为最高温度和最低温度
sub2 = sub[2].split('/')
sub.remove(sub[2])
sub.insert(2, sub2[0])
sub.insert(3, sub2[1])
sub.insert(0, cityname)
Weather = WeatherItem() # 使用items中定义的数据结构
Weather['cityname'] = sub[0]
Weather['date'] = sub[1]
Weather['tq'] = sub[2]
Weather['maxtemp'] = sub[3]
Weather['mintemp'] = sub[4]
Weather['fengli'] = sub[5]
yield Weather
结果: