小小前端浅学一下Python-7(多协程爬虫与爬虫框架)

267 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

Python专题的文章收录于专栏:Python专栏

1. 多协程(gevent库,queue模块)

利用多协程编程可以实现程序的异步运行,可以大大加快程序的运行速度

也就相当于在同一时间有多只爬虫在进行数据爬取

  • 导入模块
from gevent import monkey
monkey.patch_all()   #将程序编程协作式运行,实现异步
import gevent,requests
from gevent.queue import Queue
url_list = ['...','...','...',...]   #将网站封装成列表

1. 不使用queue

  • 首先需要定义一个执行爬虫任务的函数
def crawler(url):
    r = requests,get(url)
    print(url,r.status_code)
  • 紧接着创建任务列表,然后利用append方法逐个插入任务,插入的同时传入爬虫的函数及对应的地址,后续任务列表中的多个任务将会异步执行
tasks_list = []   #创建空的任务列表
for url in url_list:
    task = gevent.spawn(crawler,url)   #创建任务
    tasks_list.append(task)   #往任务列表添加任务
gevent.joinall(tasks_list)   #执行列表中所有任务

注意上面的这个方法,实际上就是一个地址创建了一只爬虫,毋庸置疑造成了资源的浪费,所以效率并不高

2. 使用queue(效率更高)

  • 首先创建一个队列,用于存放地址,便于后续爬虫读取要爬取数据的网址
work = Queue()   #创建队列对象
for url in url_list:
    work.put_nowait(url)   #将网址放入队列中
  • 然后定义爬取数据的函数,只要队列不为空,就从队头取出一个地址,并执行request.get函数
def crawler():
    while not work.empty():   #当队列不是空的时候,执行下面程序
        url = work.get_nowait()   #取出队列中的网址
        r = requests.get(url)
        print(url,work.qsize(),r.status_code)   #qsize()用于判断队列中数量的多少
  • 最后需要创建任务列表,这里一个任务代表着一个爬虫,在这里爬虫的数量可以自己选择,视地址数量而定,然后创建的爬虫合作先后从队列中取出地址,实现异步爬虫操作
tasks_list = []
for x in range(2):   #相当于建立两个爬虫
    task = gevent.spawn(crawler)
    tasks_list.append(task)
gevent.joinall(tasks_list)

2. Scrapy(爬虫框架)

看来不管前端后端最终的道路都是框架

Scrapy(引擎):Scheduler(调度器)、Downloader(下载器)、Spiders(爬虫)、Item Pipeline(数据管道)

用法:

  1. 创建Scrapy项目

  2. 定义item(数据)

  3. 创建和编写spiders文件

  4. 修改setting.py文件

  5. 运行Scrapy爬虫

scrapy项目结构:

  • 在终端创建Scrapy项目
d:      #路径转至D盘
cd python     #路径跳转至python文件(D:\python\)
scrapy startproject douban      #在该目录中创建一个scrapy项目 
  • 定义你将要爬取的数据item,注意这里需要导入scrapy模块

利用Field()来创建不同的属性

import scrapy
class DoubanItem(scrapy.Item):
    title = scrapy.Field()   #定义书名的数据属性
    publish = scrapy.Field()   #定义出版信息的数据属性
    score = scrapy.Field()   #定义评分的数据属性
  • 紧接着创建并编写spiders文件(这个文件是用于定义爬虫的,同时需要从上一步的items文件中引入创建的数据类)

  • 这里定义一个爬虫类,然后在类里面定义parse方法,该方法是默认处理response对象的方法

import scrapy,bs4
from ..items import DoubanItem
class DoubanSpider(scrapy.Spider):
    name = 'douban'   #定义爬虫的名字
    allowed_domains = ['book.douban.com']   #定义爬虫网站的域名
    start_urls = []
    for i in range(3):
        url = 'https://book.douban.com/top250?start='+str(i*25)
        start_urls.append(url)
    def parse(self,response):   #parse是默认处理response对象的方法
        bs = bs4.BeautifulSoup(response.text,'html.parser')
        datas = bs.find_all('tr',class_="item")
        for data in datas:
            item = DoubanItem()   #实例化DoubanItem这个类
            item['title'] = data.find_all('a')[1]['title']
            item['publish'] = data.find('p',class_='pl').text
            item['score'] = data.find('span',class_='rating_nums').text
            print(item['title'])   #把获得的item传递给引擎
            yield item
            #real_url = "..."
            #yield scrapy.Request(real_url,callback=self.parse_new)
            #构造requests对象,需要再定义一个方法处理response
  • 修改setting.py文件 在该文件里可以设置请求头、爬取速度等参数
#USER-AGENT='......'        修改请求头,将注释取消
ROBOTSTXT_OBEY = True       #将True改为False,即不遵从robots协议
#DOWNLOAD_DELAY = 0         控制爬取速度
  • 运行Scrapy爬虫(两种方式) 第一种(终端):

进入到当前框架所处目录下

执行scrapy crawl douban命令

d:   
cd python
cd douban
scrapy crawl douban

第二种:

在最外层文件中新建一个main.py文件(即与scrapy.fcg同级)

然后用execute()输入运行scrapy的命令,以列表为参数

#在最外层文件新建一个main.py文件(与scrapy.fcg同级)
#main.py中代码如下:
from scrapy import cmdline   #导入cmdline模块,控制终端命令行
cmdline.execute(['scrapy','crawl','douban'])  
  • 将爬取的数据进行存储 存储为csv文件:
#在setting.py中添加代码
FEED_URL = './storage/data/%(name)s.csv'
#FEED_URL是导出文件路径,将文件放至与main.py同级的storage文件夹中的data子文件夹里
FEED_FORMAT = 'csv'
#FEED_FORMAT是导出数据格式,得到csv格式
FEED_EXPORT_ENCODING = 'ansi'
#FEED_EXPORT_ENCODING是导出文件编码,ansi是一种在windows上的编码格式,也可变成'utf-8'用在mac电脑上

存储在excel文件:

首先需要在setting.py中取消ITEM_PIPLINES的注释

其次在piplines.py文件中写入以下代码:

#在piplines.py中:
import openpyxl
class JobuiPipline(object):
    def __init__ (self):
        self.wb = openpyxl.Workbook()
        self.ws = self.wb.active
        self.ws.append(['公司','职位',...])
    def process_item(self,item,spider):
        line = [item['...'],item['...'],...]
        self.ws.append(line)
        return item
    def close_spider(self,spider):
        self.wb.save('./jobui.xlsx')
        self.wb.close()