首先介绍一下scrapy。
Scrapy一个开源和协作的框架,是为了页面抓取所设计的,使用它可以快速、简单、可扩展(通过中间件)的方式从网站中提取所需的数据。
工作流程如下:
Scrapy Engine是scrapy的核心,负责数据流的管理。Spiders(爬虫)发出Requests请求,请求经由Scrapy Engine传递给Scheduler(调度器),Scheduler通过Downloader Middlewares(下载器中间件)传递Requests给Downloader(下载器),Downloader根据Requests从网络上下载数据,并给出结果Responses(这是爬取内容的结果),随后Downloader通过Spider Middlewares(爬虫中间件)将Response交给Spiders分析,Spiders分析得到Items交给Item Pipeline(管道)。
这里的Spider和Item Pipeline根据用户需求自行编写。(中间件也可以自行编写)
具体返回值设计可以参照官方中文文档:http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html
图片来自官方参考文档。
本次测试为爬取mcbbs整合包模块的帖子列表,并且获取每个帖子的链接,访问该链接页面并且获得主要内容标签内的文本,以“标题 : 主要mod”存入txt文本文件。
创建项目,mcbbs。
conda activate spider :激活一个python虚拟环境叫做spider,且spider这个虚拟环境目录下已经安装了scrapy。如何创建虚拟解释器环境,并且安装scrapy参见我的博客 :https://blog.csdn.net/zhouchen1998/article/details/81382006
创建成功后在对应位置生成项目文件夹,用pycharm打开,文件结构如下:
其中PackSpider为自定义爬虫。
1.首先,设置settings.py。
BOT_NAME = 'mcbbs'
SPIDER_MODULES = ['mcbbs.spiders']
NEWSPIDER_MODULE = 'mcbbs.spiders'
ITEM_PIPELINES = {
'mcbbs.pipelines.McbbsPipeline': 1,
}
STORE = 'D:\get.txt'
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 1
设置延时之类的,生成的文件里都有但是注释了,改过来就OK。
2.完成Item书写。
因为我要保存帖子名称和主要mod内容,名称获取页面元素就ok,但是主要mod则是通过获得元素的链接进入帖子获取主要内容,并且保存,所以item设计如下。
items.py
import scrapy
class McbbsItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
link_url = scrapy.Field()
dir_name = scrapy.Field()
dir_content = scrapy.Field()
3.写你的爬虫PackSpider.py(这里看清结构和继承)
自定义爬虫必须继承Spider
因为项目简单,不详细注释了。
import scrapy
from scrapy import Selector
from mcbbs.items import McbbsItem
'''
爬取mcbbs整合包区块的整合包贴名,并且通过xpath或者re(正则表达式)进入相关链接爬取所含主要mod
'''
class PackSpider(scrapy.Spider):
name = 'mc_pack'
def __init__(self):
# 帖子域名
self.server_link = 'http://www.mcbbs.net'
self.allowed_domains = ['www.mcbbs.net']
str1 = 'http://www.mcbbs.net/forum.php?mod=forumdisplay&fid=170&page='
# 产生前十列的所有链接
self.start_urls = [(str1 + str(item)) for item in range(2, 51)]
def start_requests(self):
for item in self.start_urls:
yield scrapy.Request(url=item, callback=self.parse1)
# 解析内容获得每个帖子的地址
def parse1(self, response):
hxs = Selector(response)
items = []
# 获取链接
urls = hxs.xpath(r'//a[@onclick="atarget(this)"]/@href').extract()
# 获取帖子名称
dir_names = hxs.xpath(r'//a[@onclick="atarget(this)"]/text()').extract()
for index in range(len(urls)):
item = McbbsItem()
item["link_url"] = self.server_link + "/"+ urls[index]
item["dir_name"] = dir_names[index]
items.append(item)
# 根据每个帖子链接,发送Request请求,传递item
for item in items:
yield scrapy.Request(url=item["link_url"], meta={"item": item}, callback=self.parse2)
def parse2(self, response):
item = response.meta['item']
hxs = Selector(response)
context = hxs.xpath(r'//tbody/tr[last()-2]/td/text()').extract()
item["dir_content"] = context
yield item
4.完成pipelines.py,数据落地。
# -*- 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
from mcbbs import settings
from scrapy import Request
import requests
import os
class McbbsPipeline(object):
def process_item(self, item, spider):
with open(settings.STORE, 'a') as f:
f.write(item['dir_name']+" : ")
f.write(str(item['dir_content'])+"\n")
return item
5.注意,如果你用的pycharm来项目编辑,那么必须给一个入口模块。同时scrapy是异步的爬取顺序不是输入顺序。
main.py
其中mc_pack就是spider里面定义的name。
from scrapy import cmdline
if __name__ == '__main__':
cmdline.execute('scrapy crawl mc_pack'.split())
运行结果: