成都好的网站建设公司,如何建立小程序网站,自己建设网站引流,珠海公司制作网站目录
目标
版本
实战
搭建框架
获取图片链接、书名、价格
通过管道下载数据
通过多条管道下载数据
下载多页数据 目标 掌握Scrapy框架的搭建及使用#xff0c;本文以爬取当当网魔幻小说为案例做演示。 版本 Scrapy 2.12.0 实战
搭建框架
第一步#xff1a;在D:\pyt…目录
目标
版本
实战
搭建框架
获取图片链接、书名、价格
通过管道下载数据
通过多条管道下载数据
下载多页数据 目标 掌握Scrapy框架的搭建及使用本文以爬取当当网魔幻小说为案例做演示。 版本 Scrapy 2.12.0 实战
搭建框架
第一步在D:\pytharm_workspace位置创建爬虫Scrapy项目。通过cmd在该目录执行Scrapy创建项目命令。dangdang是我的项目名称。
scrapy startproject dangdang
第二步进入项目目录并创建爬虫类。其中magic_novels是我自定义的爬虫程序名称permit.mee.gov.cn表示要爬取的网站域名。 第三步注释在settings文件中掉OBOTSTXT_OBEY协议。
#ROBOTSTXT_OBEY True
第四步打开Pycharm控制台进入项目目录。设置start_urls为我们要爬取的首页。parse表示项目启动后会自动请求start_urls中的URL。所以我们在parse方法中调试输出并运行项目。
import scrapyclass MagicNovelsSpider(scrapy.Spider):name magic_novelsallowed_domains [category.dangdang.com]start_urls [https://category.dangdang.com/cp01.03.40.00.00.00.html]def parse(self, response):print(response.url)print(response.text) scrapy crawl magic_novels 第五步此时会打印很多的无用信息我们可以在settings.py文件中设置日志级别。再次启动项目后会发现页面干净了很多。
LOG_LEVEL WARNING
scrapy crawl magic_novels
注意如果多次请求导致可能会导致缓存出现请使用以下命令
scrapy crawl magic_novels --set HTTPCACHE_ENABLEDFalse 获取图片链接、书名、价格
第一步通过xpath爬取价格、图片、书名我们先来打印调试。此时发现图片的链接不对思考是否是懒加载的一个反扒策略。 def parse(self, response):图片的链接src//ul[idcomponent_59]/li//img/src图片的名称alt//ul[idcomponent_59]/li//img/alt图书的价格price//ul[idcomponent_59]/li//p[classprice]/span考虑到所有的数据都来源于//ul[idcomponent_59]/li所以我们可以复用li对象。li_list response.xpath(//ul[idcomponent_59]/li)for li in li_list:print(f图片的链接src{li.xpath(.//img/src).extract_first()})print(f图片的名称alt{li.xpath(.//img/alt).extract_first()})print(f图书的价格price{li.xpath(.//p[classprice]/span[1]/text()).extract_first()})print(\n) 第二步 刷新页面在浏览器检查中查看第一个和最后一个发现图片链接的初始接收属性并不是src而是data-originalsrc是加载以后才代替data-original的。 第三步修改src获取的方法并再次运行项目。发现除了第一个图书的src为None其他src都正常获取了。猜测是不是第一个图书打开时没有使用懒加载。 第四步 通过调试发现确实如刚才的猜想一般第一个图书的src没有使用懒加载。修改代码后再次调试发现可以获取到第一个图书的链接。 def parse(self, response):图片的链接src//ul[idcomponent_59]/li//img/src图片的名称alt//ul[idcomponent_59]/li//img/alt图书的价格price//ul[idcomponent_59]/li//p[classprice]/span考虑到所有的数据都来源于//ul[idcomponent_59]/li所以我们可以复用li对象。li_list response.xpath(//ul[idcomponent_59]/li)for i , li in enumerate(li_list):print(f第{i1}本书。)src li.xpath(.//img/data-original).get()if src is None:src li.xpath(.//img/src).get()alt li.xpath(.//img/alt).get()price li.xpath(.//p[classprice]/span[1]/text()).get()print(f图片的链接src{src})print(f图片的名称alt{alt})print(f图书的价格price{price})print(\n) 通过管道下载数据
第一步打开items.py文件配置字段。
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.htmlimport scrapyclass DangdangItem(scrapy.Item):# 图片src scrapy.Field()# 书名name scrapy.Field()# 价格price scrapy.Field()
第二步将item类导入到爬虫程序。
import scrapyfrom dangdang.items import DangdangItemclass MagicNovelsSpider(scrapy.Spider):name magic_novelsallowed_domains [category.dangdang.com]start_urls [https://category.dangdang.com/cp01.03.40.00.00.00.html]def parse(self, response):图片的链接src//ul[idcomponent_59]/li//img/src图书的名称alt//ul[idcomponent_59]/li//img/alt图书的价格price//ul[idcomponent_59]/li//p[classprice]/span考虑到所有的数据都来源于//ul[idcomponent_59]/li所以我们可以复用li对象。li_list response.xpath(//ul[idcomponent_59]/li)for i , li in enumerate(li_list):print(f第{i1}本书。)src li.xpath(.//img/data-original).get()if src is None:src li.xpath(.//img/src).get()alt li.xpath(.//img/alt).get()price li.xpath(.//p[classprice]/span[1]/text()).get()print(f图片的链接src{src})print(f图书的名称alt{alt})print(f图书的价格price{price})print(\n)#该对象要通过管道去下载通过yield可以在每次获得book后立刻返回book给管道。bookDangdangItem(srcsrc, altalt, priceprice);yield book
第三步在settings.py中开启管道配置。管道可以有很多个并且有优先级300是默认值值越大优先级越小。
ITEM_PIPELINES {dangdang.pipelines.DangdangPipeline: 300,
}
第四步来到pipelines.py文件其中process_item方法中的item就是我们刚才在爬虫程序配置的boot对象。我们可以打印测试效果。
class DangdangPipeline:def process_item(self, item, spider):print(type(item))print(str(item))return item
scrapy crawl magic_novels 思考我们通过process_item可以获取到数据但是每次循环获取数据再重新打开文件、写入数据关闭文件明显不符合开发规范。
第五步在pipelines.py文件中配置open_spider和close_spider方法分别表示在爬虫程序执行前执行的方法和在爬虫程序执行之后执行的方法。我们可以打印日志测试。
class DangdangPipeline:#在爬虫文件开始之前就执行的方法def open_spider(self, spider):print()def process_item(self, item, spider):print(type(item))print(str(item))return item#在爬虫文件执行之后再执行的方法def close_spider(self, spider):print(----)
scrapy crawl magic_novels 第六步 下载JSON数据。
# Define your item pipelines here
#
# Dont forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
import json# useful for handling different item types with a single interface
from itemadapter import ItemAdapterclass DangdangPipeline:#在爬虫文件开始之前就执行的方法def open_spider(self, spider):self.fpopen(book.json,w,encodingutf-8)self.fp.write([)def process_item(self, item, spider):line json.dumps(dict(item), ensure_asciiFalse) ,\nself.fp.write(line)return item#在爬虫文件执行之后再执行的方法def close_spider(self, spider):# 删除最后一个多余的逗号并关闭 JSON 数组self.fp.seek(self.fp.tell() - 3, 0) self.fp.write(\n])self.fp.close()
scrapy crawl magic_novels 通过多条管道下载数据
第一步在pipelines.py文件中定义新的管道类。
#下载图片
class DangdangDownloadImgPipeline:# 在爬虫文件开始之前就执行的方法def open_spider(self, spider):passdef process_item(self, item, spider):print(item.get(src))urlhttp:item.get(src)filenameC:/Users/Administrator/Desktop/test/sanitize_filename(item.get(alt)).jpgurllib.request.urlretrieve(urlurl,filenamefilename)return item# 在爬虫文件执行之后再执行的方法def close_spider(self, spider):passdef sanitize_filename(filename):替换 Windows 文件名中不合法的字符为下划线。# 定义 Windows 文件名不允许的字符invalid_chars r[\\/:*?|]# 使用正则表达式将非法字符替换为下划线return re.sub(invalid_chars, _, filename)
第二步在settings.py中定义该管道类的优先级。
ITEM_PIPELINES {dangdang.pipelines.DangdangPipeline: 300,dangdang.pipelines.DangdangDownloadImgPipeline: 300,
}
第三步执行下载操作可以看到JSON数据和图片都下载成功了。
scrapy crawl magic_novels 下载多页数据
思考目前我们只是下载了第一页的数据能否通过配置页码下载多个页面的数据呢
第一步去页面点击下一页发现链接都差不多区别在于pg后面的跟的页码。
https://category.dangdang.com/pg2-cp01.03.40.00.00.00.html
https://category.dangdang.com/pg3-cp01.03.40.00.00.00.html
第二步在爬虫程序中设置基础的url和页码页码初始化为第一页。
class MagicNovelsSpider(scrapy.Spider):name magic_novelsallowed_domains [category.dangdang.com]start_urls [https://category.dangdang.com/cp01.03.40.00.00.00.html]base_urlhttps://category.dangdang.com/pgpage_num1;
第三步在parse方法中递归请求当当网每次请求都将url的页码改变。注意递归逻辑写在循环之外。
import scrapyfrom dangdang.items import DangdangItemclass MagicNovelsSpider(scrapy.Spider):name magic_novelsallowed_domains [category.dangdang.com]start_urls [https://category.dangdang.com/cp01.03.40.00.00.00.html]base_urlhttps://category.dangdang.com/pgpage_num1;def parse(self, response):图片的链接src//ul[idcomponent_59]/li//img/src图书的名称alt//ul[idcomponent_59]/li//img/alt图书的价格price//ul[idcomponent_59]/li//p[classprice]/span考虑到所有的数据都来源于//ul[idcomponent_59]/li所以我们可以复用li对象。li_list response.xpath(//ul[idcomponent_59]/li)for i , li in enumerate(li_list):print(f第{i1}本书。)src li.xpath(.//img/data-original).get()if src is None:src li.xpath(.//img/src).get()alt li.xpath(.//img/alt).get()price li.xpath(.//p[classprice]/span[1]/text()).get()print(f图片的链接src{src})print(f图书的名称alt{alt})print(f图书的价格price{price})print(\n)#该对象要通过管道去下载通过yield可以在每次获得book后立刻返回book给管道。bookDangdangItem(srcsrc, altalt, priceprice);yield bookif self.page_num3:self.page_num1urlself.base_urlstr(self.page_num)-cp01.03.40.00.00.00.html;#GET请求yield scrapy.Request(urlurl, callbackself.parse)
第四步运行项目。发现可以正常下载前三页的数据。