目的意义
爬虫框架也许能简化工作量, 提高效率等. scrapy 是一款方便好用, 拓展方便的框架.
本文将使用 scrapy 框架, 示例爬取自己博客中的文章内容.
说明
创建 scrapy 工程
首先当然要确定好, 有没有完成安装 scrapy. 在 Windows 下, 使用 pip install scrapy, 慢慢等所有依赖和 scrapy 安装完毕即可. 然后输入 scrapy 到 cmd 中测试.
建立工程使用 scrapy startproject myTestProject, 会在工程下生成文件.
一些介绍说明
在生成的文件中,
创建爬虫模块 - 下载
在路径./myTestProject/spiders 下, 放置用户自定义爬虫模块, 并定义好 name,start_urls,parse().
如在 spiders 目录下建立文件 CnblogSpider.py, 并填入以下:
- import scrapy
- class CnblogsSpider(scrapy.Spider):
- name="cnblogs"
- start_urls=["https://www.cnblogs.com/bai2018/default.html?page=1"]
- def parse(self,response):
- pass
在 cmd 中, 切换到./myTestProject/myTestProject 下, 再执行 scrapy crawl cnblogs(name) 测试, 观察是否报错, 响应代码是否为 200. 其中的 parse 中参数 response 用于解析数据, 读取数据等.
强化爬虫模块 - 解析
在 CnblogsSpider 类中的 parse 方法下, 添加解析功能. 通过 xpath,CSS,extract,re 等方法, 完成解析.
调取元素审查分析以后添加, 成为以下代码:
- import scrapy
- class CnblogsSpider(scrapy.Spider):
- name="cnblogs"
- start_urls=["https://www.cnblogs.com/bai2018/"]
- def parse(self,response):
- papers=response.xpath(".//*[@class='day']")
- for paper in papers:
- url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
- title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
- time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
- content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
- print(url,title,time,content)
- pass
找到页面中, class 为 day 的部分, 然后再找到其中各个部分, 提取出来, 最后通过 print 方案输出用于测试.
在正确的目录下, 使用 cmd 运行 scrapy crawl cnblogs, 完成测试, 并观察显示信息中的 print 内容是否符合要求.
强化爬虫模块 - 包装数据
包装数据的目的是存储数据. scrapy 使用 Item 类来满足这样的需求.
框架中的 items.py 用于定义存储数据的 Item 类.
在 items.py 中修改 MytestprojectItem 类, 成为以下代码:
- import scrapy
- class MytestprojectItem(scrapy.Item):
- # define the fields for your item here like:
- # name = scrapy.Field()
- url=scrapy.Field()
- time=scrapy.Field()
- title=scrapy.Field()
- content=scrapy.Field()
- pass
然后修改 CnblogsSpider.py, 成为以下内容:
- import scrapy
- from myTestProject.items import MytestprojectItem
- class CnblogsSpider(scrapy.Spider):
- name="cnblogs"
- start_urls=["https://www.cnblogs.com/bai2018/"]
- def parse(self,response):
- papers=response.xpath(".//*[@class='day']")
- for paper in papers:
- url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
- title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
- time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
- content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
- item=MytestprojectItem(url=url,title=title,time=time,content=content)
- yield item
- pass
将提取出的内容封装成 Item 对象, 使用关键字 yield 提交.
强化爬虫模块 - 翻页
有时候就是需要翻页, 以获取更多数据, 然后解析.
修改 CnblogsSpider.py, 成为以下内容:
- import scrapy
- from scrapy import Selector
- from myTestProject.items import MytestprojectItem
- class CnblogsSpider(scrapy.Spider):
- name="cnblogs"
- allowd_domains=["cnblogs.com"]
- start_urls=["https://www.cnblogs.com/bai2018/"]
- def parse(self,response):
- papers=response.xpath(".//*[@class='day']")
- for paper in papers:
- url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
- title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
- time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
- content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
- item=MytestprojectItem(url=url,title=title,time=time,content=content)
- yield item
- next_page=Selector(response).re(u'<a href="(\S*)"> 下一页 </a>')
- if next_page:
- yield scrapy.Request(url=next_page[0],callback=self.parse)
- pass
在 scrapy 的选择器方面, 使用 xpath 和 CSS, 可以直接将 CnblogsSpider 下的 parse 方法中的 response 参数使用, 如 response.xpath 或 response.CSS.
而更通用的方式是: 使用 Selector(response).xxx. 针对 re 则为 Selector(response).re.
关于 yield 的说明:
强化爬虫模块 - 存储
当 Item 在 Spider 中被收集时候, 会传递到 Item Pipeline.
修改 pipelines.py 成为以下内容:
- import JSON
- from scrapy.exceptions import DropItem
- class MytestprojectPipeline(object):
- def __init__(self):
- self.file=open('papers.json','wb')
- def process_item(self, item, spider):
- if item['title']:
- line=JSON.dumps(dict(item))+"\n"
- self.file.write(line.encode())
- return item
- else:
- raise DropItem("Missing title in %s"%item)
重新实现 process_item 方法, 收集 item 和该 item 对应的 spider. 然后创建 papers.JSON, 转化 item 为字典, 存储到 JSON 表中.
另外, 根据提示打开 pipelines.py 的开关. 在 settings.py 中, 使能 ITEM_PIPELINES 的开关如下:
然后在 cmd 中执行 scrapy crawl cnblogs 即可
另外, 还可以使用 scrapy crawl cnblogs -o papers.CSV 进行存储为 CSV 文件.
需要更改编码, 将 CSV 文件以记事本方式重新打开, 更正编码后重新保存, 查看即可.
强化爬虫模块 - 图像地址
设定 setting.py
- ITEM_PIPELINES = {
- 'myTestProject.pipelines.MytestprojectPipeline':300,
- 'scrapy.pipelines.images.ImagesPipeline':1
- }
- IAMGES_STORE=".//cnblogs"
- IMAGES_URLS_FIELD = 'cimage_urls'
- IMAGES_RESULT_FIELD = 'cimages'
- IMAGES_EXPIRES = 30
- IMAGES_THUMBS = {
- 'small': (50, 50),
- 'big': (270, 270)
- }
修改 items.py 为:
- import scrapy
- class MytestprojectItem(scrapy.Item):
- # define the fields for your item here like:
- # name = scrapy.Field()
- url=scrapy.Field()
- time=scrapy.Field()
- title=scrapy.Field()
- content=scrapy.Field()
- cimage_urls=scrapy.Field()
- cimages=scrapy.Field()
- pass
修改 CnblogsSpider.py 为:
- import scrapy
- from scrapy import Selector
- from myTestProject.items import MytestprojectItem
- class CnblogsSpider(scrapy.Spider):
- name="cnblogs"
- allowd_domains=["cnblogs.com"]
- start_urls=["https://www.cnblogs.com/bai2018/"]
- def parse(self,response):
- papers=response.xpath(".//*[@class='day']")
- for paper in papers:
- url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()[0]
- title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
- time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
- content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
- item=MytestprojectItem(url=url,title=title,time=time,content=content)
- request=scrapy.Request(url=url, callback=self.parse_body)
- request.meta['item']=item
- yield request
- next_page=Selector(response).re(u'<a href="(\S*)"> 下一页 </a>')
- if next_page:
- yield scrapy.Request(url=next_page[0],callback=self.parse)
- pass
- def parse_body(self, response):
- item = response.meta['item']
- body = response.xpath(".//*[@class='postBody']")
- item['cimage_urls'] = body.xpath('.//img//@src').extract()
- yield item
启动爬虫
建立 main 函数, 传递初始化信息, 导入指定类. 如:
- from scrapy.crawler import CrawlerProcess
- from scrapy.utils.project import get_project_settings
- from myTestProject.spiders.CnblogSpider import CnblogsSpider
- if __name__=='__main__':
- process = CrawlerProcess(get_project_settings())
- process.crawl('cnblogs')
- process.start()
来源: https://www.cnblogs.com/bai2018/p/11255185.html