python爬虫系列之Scrapy框架¶
1.创建项目¶
scrapy startproject jianshu_article
2.创建爬虫程序¶
2.1 自动创建¶
cd jianshu_article
scrapy genspider jianshu jianshu.com
2.2 手动创建¶
为了创建一个Spider,您必须继承 scrapy.Spider 类, 且定义以下三个属性:
name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。
start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。
parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。
3.设置数据模型¶
Item 是保存爬取到的数据的容器;其使用方法和python字典类似, 并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。
class JianshuArticleItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
avatar = scrapy.Field() # 头像
nickname = scrapy.Field() # 昵称
write_love = scrapy.Field() # 字数及喜欢
fan = scrapy.Field() # 粉丝
force = scrapy.Field() # 关注
4.分析页面源码,编写爬虫¶
jianshu.py
# -*- coding: utf-8 -*-
import scrapy
from jianshu_article.items import JianshuArticleItem
class JianshuSpider(scrapy.Spider):
name = 'jianshu'
allowed_domains = ['jianshu.com']
user_id = "1b4c832fb2ca"
url = "https://www.jianshu.com/u/{0}?page=1".format(user_id)
start_urls = [
url,
]
def parse(self, response):
'''
不写extract()打印出来就是Selector对象,加上extract()
就是返回一个list对象,里面为对应的value,
取值可通过.extract()[index]来取得。
'''
# 用户头像
avatar = response.xpath('//div[@class="avatar"]/img/@src').extract()
# 昵称
nickname = response.xpath('//div[@class="author-info"]/div[@class="name"]/text()').extract()
# 关注及粉丝
force_fan = response.xpath('//div[@class="author-info"]/div[@class="follow-meta"]/span/text()').extract()
# 字数及喜欢
write_love = response.xpath('normalize-space(//div[@class="author-meta"]/text())').extract() # normalize-space去除所有回车换行
item = JianshuArticleItem()
item['avatar'] = avatar[0]
item['nickname'] = nickname[0]
item['write_love'] = write_love[0]
item['force'] = force_fan[0]
item['fan'] = force_fan[1]
print(item)
yield item
5.运行Scrapy¶
scrapy crawl spider的name
这里是:
scrapy crawl jianshu
6.运行后错误解决¶
USER_AGENT = 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Mobile Safari/537.36'
CONCURRENT_REQUESTS = 1 #并发数
DOWNLOAD_DELAY = 5 #为了防止IP被封,我们5秒请求一次
HTTPERROR_ALLOWED_CODES = [403] #上面报的是403,就把403加入
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
7.数据存储至csv¶
7.1 修改pipelines.py¶
import json
class JianshuArticlePipeline(object):
def open_spider(self, spider):
self.file = open('jianshu.json','w',encoding='utf-8') # encoding设置编码格式,否则保存的中文会乱码
def process_item(self, item, spider):
if(type(item)!=dict):
item = dict(item)
str_data = json.dumps(item,ensure_ascii=False) + ',\n'
self.file.write(str_data)
return item
def close_spider(self, spider):
self.file.close()
7.2 setting.py设置¶
ITEM_PIPELINES = {
'jianshu_article.pipelines.JianshuArticlePipeline': 300,
}