数据来源:
目标描述:
建立一个爬虫项目,抓取豆瓣读书Top 250页面的250本书的信息,采集字段包括:
- 书的图片
- 书名
- 作者
- 出版社
- 价格
- 评分
- 简介
开始爬虫
1.新建项目
scrapy startproject douban
进入项目
cd douban
2.编写item.py文件,定义将要爬取的字段
import scrapy
class DoubanItem(scrapy.Item):
img = scrapy.Field() # 书的图片地址
book_name = scrapy.Field() # 书名
english_name = scrapy.Field() # 英文名
author = scrapy.Field() # 作者
publish = scrapy.Field() # 出版社
price = scrapy.Field() # 价格
score = scrapy.Field() # 评分
description = scrapy.Field() # 简介
pass
3.创建并编写doubanspider.py文件
通过css选择路径:
# -*- coding: utf-8 -*-
import scrapy
from douban.items import DoubanItem
class DoubanspiderSpider(scrapy.Spider):
name = 'doubanspider'
# allowed_domains = ['https://www.douban.com/']
start_urls = ['https://book.douban.com/top250',]
def parse(self, response):
for book in response.css('tr.item'):
item = DoubanItem()
item['img'] = book.css('a.nbg img::attr(src)').extract_first()
item['book_name'] = book.css('div.pl2 a::attr(title)').extract()
item['english_name'] = book.css('div.pl2 span::text').extract_first()
item['author'] = book.css('p.pl::text').extract_first().split('/')[0]
item['publish'] = book.css('p.pl::text').extract_first().split('/')[-3]
item['price'] = book.css('p.pl::text').extract_first().split('/')[-1]
item['score'] = book.css('div.star.clearfix span.rating_nums::text').extract_first()
item['description'] = book.css('p.quote span.inq::text').extract_first()
yield item
next_link = response.css("div.paginator span.next a::attr(href)").extract_first() # 得到下一页网址的起始数字
# 查看是否有下一页
if next_link is not None:
next_link = next_link.split('?')[-1]
next_page = '?' + next_link
next_page = response.urljoin(next_page) # 生成下一页的链接
yield scrapy.Request(next_page,callback=self.parse) # 访问下一页
通过xpath选择路径:
import scrapy
from douban.items import DoubanItem
class DoubanspiderSpider(scrapy.Spider):
name = 'doubanspider'
# allowed_domains = ['https://www.douban.com/']
start_urls = ['https://book.douban.com/top250',]
def parse(self, response):
for book in response.xpath(".//div[@class='article']//table"):
item = DoubanItem()
item['img'] = book.xpath(".//a/img/@src").extract_first()
item['book_name'] = book.xpath(".//div[@class='pl2']/a/@title").extract_first().strip()
item['english_name'] = book.xpath(".//div[@class='pl2']/span/text()").extract()
item['author'] = book.xpath(".//p[@class='pl']/text()").extract_first().split('/')[0]
item['publish'] = book.xpath(".//p[@class='pl']/text()").extract_first().split('/')[-3]
item['price'] = book.xpath(".//p[@class='pl']/text()").extract_first().split('/')[-1]
item['score'] = book.xpath(".//span[@class='rating_nums']/text()").extract_first()
item['description'] = book.xpath(".//p[@class='quote']/span/text()").extract_first()
yield item
next_link = response.xpath("..//div[@class='paginator']//span[@class='next']/a/@href") # 得到下一页网址的起始数字
# 查看是否有下一页
if next_link:
next_link = next_link.extract_first().split('?')[-1]
next_page = '?' + next_link
next_page = response.urljoin(next_page) # 生成下一页的链接
yield scrapy.Request(next_page,callback=self.parse) # 访问下一页
4.开始爬虫,并保存到data.json文件
scrapy crawl doubanspider -o data.json
查看获取的数据数量,获取到250条数据。
查看json文件:
采集过程中遇到的几个问题:
问题1:使用scrapy shell查看xpath路径是否正确提取到数据时无法连接到目标网站
在命令行输入
scrapy shell "https://book.douban.com/top250"
返回结果:
可以看到,申请访问豆瓣读书页面的HTTP返回状态码是403,说明豆瓣设置了反爬虫机制,会检查访问者的user-agent信息,因此个人爬虫无法抓取数据。
解决办法
1. 连接时在命令上加上 -s USER_AGENT='Mozilla/5.0',即
scrapy shell -s USER_AGENT='Mozilla/5.0' "https://book.douban.com/top250"
返回状态码为200,成功访问到页面。这种方法简单但是每次操作时都要加上这段代码比较繁琐。
2. 修改scrapy的user-agent默认值
我的参考:Scrapy shell调试返回403错误 - CSDN博客
首先找到python的:安装目录下的default_settings.py文件,比如我的在D:\Program Files\python\Lib\site-packages\scrapy\settings\default_settings.py
把
USER_AGENT = 'Scrapy/%s (+http://scrapy.org)' % import_module('scrapy').__version__
改为
USER_AGENT = 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0'
则再次访问此类网站时,可以正常访问html不会在出现403错误了。这种修改主要是更改自己的user-agent信息,伪装成浏览器进行访问。
问题2:下一页的链接构建正确,但是无法访问下一页的链接从而无法循环采集数据
查阅各种资料后发现我的下面这行代码有误,注释掉即可:
allowed_domains = ['https://www.douban.com/'] # 包含构成许可域的基础URL,供蜘蛛去爬,不在此允许范围内的域名就会被过滤,而不会进行爬取
而我要访问的网页
https://book.douban.com/top250?start=0
是不在允许域的,因此出现错误。
需要说明的一点:虽然设置了允许域进行过滤,但是不会过滤start_urls的网址,因此首页数据可以获取到,只是无法进行循环抓取。