网络安全 基于scrapy框架与selenium、openpyxl库爬取国外各国家疫情统计汇总信息
数据来源
https://voice.baidu.com/act/newpneumonia/newpneumonia/
思路
由于目标页面中的数据是动态加载出来的,所以直接发起请求得到的响应是不包含任何有用数据的,所以需要使用selenium的浏览器驱动器进行请求发送并获得包含数据的响应。同时继续观察页面发现,初始加载的页面只包含前面一部分数据,剩余数据需要手动点击“展开全部”才能加载全部数据,所以还需要使用动作链进行模拟点击操作。获取到的响应解析后都存储到excel表格中,方便后续的使用。
起始url即为目标网站,但是此次请求获得的响应是不包含数据的,所以不能直接将该响应用于解析,需要在下载中间件中进行拦截和篡改。下载中间件拦截后由浏览器驱动器再次对该网站发起请求,然后使用动作链,找到并模拟点击“展开全部”,获得到包含完整数据的响应,再将该响应封装后返回给爬虫进行解析。
def process_response(self, request, response, spider):
# Called with the response returned from the downloader.
# Must either;
# - return a Response object
# - return a Request object
# - or raise IgnoreRequest
print('开始请求……')
spider.bro.get(request.url) # 拦截响应,重新请求获取完整响应
actions = ActionChains(spider.bro)
actions.click(spider.bro.find_element_by_xpath('//*[@id="foreignTable"]/div/span')).perform() # 点击“展开全部”
actions.release() # 释放动作链
page_text = spider.bro.page_source
new_response = http.HtmlResponse(url=request.url, body=page_text, encoding='utf-8', request=request) # 篡改响应为新请求的完整的页面
return new_response
使用xpath对响应进行解析,解析到的数据存储在item中提交给管道。
class NewCoronaCrawlerItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
area = scrapy.Field() # 地区
new = scrapy.Field() # 新增
total = scrapy.Field() # 累计
cured = scrapy.Field() # 治愈
death = scrapy.Field() # 死亡
def parse(self, response, **kwargs):
print('开始解析……')
tr_list = response.xpath('//*[@id="foreignTable"]/table/tbody/tr/td/table/tbody/tr')
for tr in tr_list:
data = tr.xpath('./td//text()').getall()
item = NewCoronaCrawlerItem()
item['area'] = data[0]
item['new'] = data[1]
item['total'] = data[2]
item['cured'] = data[3]
item['death'] = data[4]
yield item
管道中使用openpyxl打开excel表格,新建一个工作表,并命名为“年-月-日_时-分-秒”,将所有数据写入并保存后关闭。
class NewCoronaCrawlerPipeline:
wb = None
ws = None
def open_spider(self, spider):
self.wb = openpyxl.load_workbook(r'新型冠状病毒肺炎国外各国家疫情统计汇总.xlsx') # 打开工作簿
self.ws = self.wb.create_sheet(time.strftime('%Y-%m-%d_%H-%M-%S', time.localtime(time.time()))) # 新建工作表,命名为年月日时分秒
self.ws.append(['地区', '新增', '累计', '治愈', '死亡']) # 插入表头
def process_item(self, item, spider):
self.ws.append([item['area'], int(item['new']), int(item['total']), int(item['cured']), int(item['death'])]) # 插入一行数据
return item
def close_spider(self, spider):
print('保存数据……')
self.wb.save(r'新型冠状病毒肺炎国外各国家疫情统计汇总.xlsx')
self.wb.close()
print('保存完成!')
同时为了提高效率可以将浏览器驱动器设置为无头浏览器,并且设置规避检测提高安全性。
def __init__(self):
super().__init__()
# 设置为无头浏览器
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 规避检测
option = webdriver.ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
self.bro = webdriver.Chrome(executable_path=r'chromedriver.exe', options=option, chrome_options=chrome_options)
对于起始请求,需要修改配置文件中的信息不遵守robots.txt协议,并且进行UA伪装,同时开启下载中间件和管道,修改显示的日志等级。
结果