在Scrapy的整个架构中,引擎是可以说有着最高的权利,管理着调度器、下载器、爬虫和数据管道四个重要的组成部分。
这四个组成部分都听命于引擎,一丝不苟的执行引擎下发的命令。
本次,我们使用Scrapy爬取职友集的招聘信息,让我们更加熟练的掌握Scrapy的用法。
一、明确目标
职友集可以通过索引的方式,搜索到全国上百家招聘网站的最新职位:https://www.jobui.com/rank/company/
我们要获取排行榜中的公司名称、招聘职位名称、工作地点和招聘要求。
二、代码实现
(1)创建项目
在命令行或终端中,cd到想要保存爬虫的目录下,输入创建scrapy项目的命令:scrapy startproject class14(名称可自定义)。
然后在蹦迪电脑的编译器中打开这个scrapy项目,如下所示:
(2)定义items
在items.py文件中,定义Items:
import scrapy
# 定义一个继承自scrapy.Item的Class14Item类
class Class14Item(scrapy.Item):
# 定义公司名称的数据属性
company = scrapy.Field()
# 定义职位名称的数据属性
position = scrapy.Field()
# 定义工作地点的数据属性
address = scrapy.Field()
# 定义招聘要求的数据属性
info = scrapy.Field()
(3)创建和编写爬虫文件
在spiders文件夹下创建爬虫文件,我们将它命名为Jobhui_Info。
import scrapy
import bs4
from ..items import Class14Item
# 定义爬虫类Jobhui_Info
class Jobhui_Info(scrapy.Spider):
# 定义爬虫的名称
name = 'Jobhui_Info'
# 定义允许爬虫爬取网址的域名
allowed_domains = ['www.jobhui.com']
# 定义起始网址
start_urls = ['https://www.jobhui.com/rank/company']
def parse(self, response):
# 使用beautifulsoup解析response
bs = bs4.BeautifulSoup(response.text,'html.parser')
# 提取1-10的公司,用find_all提取<ul class_="textList flsty cfix">标签
ul_list = bs.find_all('div',class_='textlist flsty cfix')
for ul in ul_list:
a_list = ul.find_all('a')
for a in a_list:
# 提取出<a>标签的href属性的值,即公司id标识
company_id = a['href']
# 构造出包含公司名称和招聘信息的网址链接的list
url = 'https://www.jobhui.com{}jobs'.format(company_id)
接下来,我们要获取不同公司的招聘职位信息。
从这里开始,就需要重新构造新的requests对象和定义新的方法处理response。
import scrapy
import bs4
from ..items import Class14Item
# 定义爬虫类Jobhui_Info
class Jobhui_Info(scrapy.Spider):
# 定义爬虫的名称
name = 'Jobhui_Info'
# 定义允许爬虫爬取网址的域名
allowed_domains = ['www.jobhui.com']
# 定义起始网址
start_urls = ['https://www.jobhui.com/rank/company']
def parse(self, response):
# 使用beautifulsoup解析response
bs = bs4.BeautifulSoup(response.text,'html.parser')
# 提取1-10的公司,用find_all提取<ul class_="textList flsty cfix">标签
ul_list = bs.find_all('div',class_='textlist flsty cfix')
for ul in ul_list:
a_list = ul.find_all('a')
for a in a_list:
# 提取出<a>标签的href属性的值,即公司id标识
company_id = a['href']
# 构造出包含公司名称和招聘信息的网址链接的list
url = 'https://www.jobhui.com{}jobs'.format(company_id)
# 用yield语句把构造好的request对象传递给引擎。
# 用scrapy.Request构造request对象。callback参数设置调用parse_Jobhui_Info方法。
yield scrapy.Request(url, callback=self.parse_Jobhui_Info)
# 定义新的处理response的方法parse_Jobhui_Info
def parse_Jobhui_Info(self,response):
# 解析源码数据
bs = bs4.BeautifulSoup(response.text,'html.parser')
# 获取公司名称
comany = bs.find(class_='company-banner-name')
# 获取招聘信息的列表
datas = bs.find_all('div', class_='job-simple-content')
# 遍历datas
for data in datas:
# 实例化Class14Item类
item = Class14Item()
# 将公司名称放回Class14Item类的company属性
item['company'] = comany
# 提取职位名称,并放回Class14Item类的position属性
item['position'] = data.find_all('div', class_="job-segmetation")[0].find('h3').text
# 提取出工作地点,并把这个数据放回Class14Item类的address属性里
item['address'] = data.find_all('div', class_="job-segmetation")[1].find_all('span')[0].text
# 提取出招聘要求,并把这个数据放回Class14Item类的detail属性里
item['info'] = data.find_all('div', class_="job-segmetation")[1].find_all('span')[1].text
# 用yield语句把item传递给引擎
yield item
其中的部分代码解释一下:
scrapy.Request是构造requests对象的类。url是我们往requests对象里传入的每家公司招聘信息网址的参数。
- callback的中文意思是回调。self.parse_Jobhui_Info是我们新定义的parse_Jobhui_Info方法。往requests对象里传入callback=self.parse_GetJobInfo这个参数后,引擎就能知道response要前往的下一站,是用parse_Jobhui_Info()方法来解析传入的新参数。
- yield的作用就是把这个构造好的requests对象传递给引擎。
(4)存储文件
Scrapy可以支持把数据存储成csv文件或者Excel文件:
- 存储成csv文件的方法比较简单,只需在settings.py文件里,添加如下的代码即可:
FEED_URI = '%(Jobhui_Info)s.csv'
FEED_FORMAT = 'CSV'
FEED_EXPORT_ENCODING = 'ansi'
- FEED_URI是导出文件的路径。’%(Jobhui_Info)s.csv’,是把CSV文件放到与settings.py文件同级的文件夹内。
- FEED_FORMAT 是导出数据格式,写CSV就能得到CSV格式。
- FEED_EXPORT_ENCODING 是导出文件编码,ansi是一种在windows上的编码格式,你也可以把它变成utf-8用在mac电脑上。
需要注意:在最新的scrapy版本2.1.0不支持这种方式。需要降级到1.8.0版本才能存储进csv文件中。
- 存储成Excel文件,相对复杂一些。实现步骤如下:
- 先在setting.py里设置启用ITEM_PIPELINES。取消掉ITEM_PIPLINES的注释即可。
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'class14.pipelines.Class14Pipeline': 300,
}
- 在piplines.py文件中,编辑代码。依然是使用openpyxy来实现对数据的保存。
import openpyxl
# 定义一个 Class14Pipeline
class Class14Pipeline(object):
# 初始化函数,当类实例化时该方法自动启动
def __init__(self):
# 创建工作簿
self.wb = openpyxl.Workbook()
# 定位工作表
self.ws = self.wb.active
# 使用append函数往表格中添加表头
self.ws.append(['公司','职位','地址','招聘信息'])
# process_item是默认的处理item的方法,就像parse是默认处理response的方法
def process_item(self,item,spider):
# 把公司名称、职位名称、工作地点和招聘要求都写成列表的形式,赋值给line
line = [item['company'],item['position'],item['address'],item['info']]
# 用append函数把公司名称、职位名称、工作地点和招聘要求的数据都添加进表格
self.ws.append(line)
# 将item给回引擎,如果后面还有这个item需要经过的itempipeline,引擎会自己调度
return item
# close_spider是当爬虫结束运行时,这个方法就会执行
def close_spider(self, spider):
# 保存文件
self.wb.save('Jobhui_Info.xlsx')
# 关闭文件
self.wb.close()
(5)修改设置
在settings.py文件里添加请求头,以及把ROBOTSTXT_OBEY=True改成ROBOTSTXT_OBEY=False。
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36'}
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
同时,我们要将#DOWNLOAD_DELAY = 3这行取消注释,同时对DOWNLOAD_DELAY这个参数的值进行修改。
DOWNLOAD_DELAY的意思是下载延迟,这个参数的作用是控制爬虫的速度。3秒对于这个项目来说太慢了,我们要把下载延迟的时间改成0.5秒。
# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 0.5
三、练习
- 使用scrapy爬取豆瓣图TOP250前2页的书籍的短评数据(包括书名、评论ID、短评内容),并存储成Excel文件。
(1)创建项目
在cmd窗口,cd到所在文件夹:“scrapy startproject Doubanbook_Comments"
(2)定义Item
在Items.py文件中,输入下列代码:
import scrapy
class DoubanbookCommentsItem(scrapy.Item):
# 定义书籍名称的数据属性
name = scrapy.Field()
# 定义评论ID的数据属性
commentID = scrapy.Field()
# 定义短评内容点的数据属性
comment = scrapy.Field()
(3)创建和编写爬虫文件
在spiders文件夹下,新建文件Doubanbook_Comments.py。并编写代码如下:
import scrapy
import bs4
from ..items import DoubanbookCommentsItem
# 定义一个爬虫类doubanbookComments
class Doubanbook_Comments(scrapy.Spider):
# 定义爬虫名字
name = 'Doubanbook_Comments'
# 定义允许爬虫爬取的网址
allowed_domains = ['book.douban.com']
# 定义起始网址
start_urls = []
# 根据豆瓣图书的url规律,取前3页的Url,并添加进起始网址中(只取第一页的书籍)
for i in range(1):
url = 'https://book.douban.com/top250?start={}'.format(i*25)
start_urls.append(url)
# 定义parse方法,获取每本书籍详情页的链接
def parse(self, response):
bs = bs4.BeautifulSoup(response.text,'html.parser')
url_list = bs.find_all('div',class_="pl2")
for url in url_list:
# <a>标签的值就是书籍详情页的链接
book_url = url.find('a')['href']
# 为不给网站造成负担,仅抓取第一页的短评内容
for i in range(1,2):
comment_url = '{}comments/new?p={}'.format(book_url,i)
# 用yield语句把构造好的request对象传递给引擎
yield scrapy.Request(comment_url,callback=self.parse_Get_bookomments)
# 定义新的处理方法parse_Get_bookcomments
def parse_Get_bookcomments(self, response):
bs = bs4.BeautifulSoup(response.text,'html.parser')
# 提取到书名
name = bs.find('h1').text.replace(' 短评','')
# 提取到书籍评论列表
comment_list = bs.find_all('div',class_='comment')
# 遍历列表
for comment in comment_list:
# 实例化DoubanbookCommentsItem类
item = DoubanbookCommentsItem()
# 将书籍名称放回DoubanbookCommentsItem类中
item['name'] = name
# 将评论人名称放回DoubanbookCommentsItem类
item['commentID'] = comment.find('span',class_='comment-info').find('a').text
item['comment'] = comment.find('span',class_='short').text
# 使用yield语句把item传递给引擎
yield item
(4)存储文件
- 在setting.py文件中,将ITEM_PIPELINES的注释去掉。
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'Doubanbook_Comments.pipelines.DoubanbookCommentsPipeline': 300,
}
- 在pipelines.py文件中,使用openpyxy来实现对数据的存储。
import openpyxl
# 定义一个DoubanbookCommentsPipeline类,负责处理item
class DoubanbookCommentsPipeline(object):
# 初始化函数,当类实例化时,自动启动该方法
def __init__(self):
# 创建工作簿
self.wb = openpyxl.Workbook()
# 创建工作表
self.ws = self.wb.active
# 添加表头
self.ws.append(['书籍名称', '评论人', '评论内容'])
# process_item是默认的处理item的方法,就像parse是默认处理response的方法
def process_item(self, item, spider):
# 将书籍名称、评论人、评论内容赋值
line = [item['name'], item['commentID'], item['comment']]
# 将对应的数据添加进表格中
self.ws.append(line)
return item
# close_spider是当爬虫结束运行时,这个方法就会执行
def close_spider(self, spider):
# 保存文件
self.wb.save('douban_bookcomments.xlsx')
# 关闭文件
self.wb.close()
(5)修改设置
在settings.py文件中,添加请求头,把ROBOTSTXT_OBEY=True改成ROBOTSTXT_OBEY=False。
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36'}
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
同时修改一下下载延迟时间,调整到0.5秒
# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 0.5
- 使用Scrapy,爬取当当网2018年图书销售榜单前3页的数据,包括排名、图书名、作者、出版社、书的原价、价格折扣、折扣价、评价数量。
网址: http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-year-2019-0-1-1
实现步骤
1. 创建项目
在CMD中,cd到项目所在文件夹,创建项目,命名为DDbook。
scrapy startproject DDbook
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tV3ajZXJ-1592558823816)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3560fb1c-7733-4faa-9577-656c26190507/Untitled.png)]
2. 定义items
在items.py文件中,定义items。
import scrapy
class DdbookItem(scrapy.Item):
# 定义书籍排名的数据属性
num = scrapy.Field()
# 定义书籍名称的数据属性
name = scrapy.Field()
# 定义作者的数据属性
author = scrapy.Field()
# 定义出版社的数据属性
publish = scrapy.Field()
# 定义书原价的数据属性
price = scrapy.Field()
# 定义书籍折扣的数据属性
discount = scrapy.Field()
# 定义折扣价的数据属性
dis_price = scrapy.Field()
# 定义评价数量的数据属性
rating_num = scrapy.Field()
3. 创建和编写爬虫文件
在spiders文件夹下,创建DDbook.py文件,在其中编写爬虫代码:
import scrapy
import bs4
from ..items import DDbookItem
# 定义爬虫类DDbook,继承自scrapy.Spider
class DDbook(scrapy.Spider):
# 定义爬虫的名称
name = 'DDbook'
# 定义允许爬虫爬取网址的域名
allowed_domains = ['http://bang.dangdang.com']
# 定义起始网页
start_urls = []
for i in range(1, 4):
url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-year-2019-0-1-{}'.format(i)
start_urls.append(url)
def parse(self, response):
# 使用bs4解析数据
bs = bs4.BeautifulSoup(response.text, 'html.parser')
# 提取所有书籍的列表
li_list = bs.find('ul', class_='bang_list clearfix bang_list_mode').find_all('li')
# 遍历列表
for book in li_list:
# 实例化DDbook对象
item = DDbookItem()
# 将书籍排名放回DDbook的num属性
item['num'] = book.find_all('div')[0].text.replace('.', '')
# 将书籍名称放回DDbook类的name属性
item['name'] = book.find('div', class_='name').find('a')['title']
# 将作者放回DDbook类的author属性
# 部分书籍没有作者,使用异常捕捉
try:
item['author'] = book.find_all('div', class_='publisher_info')[0].find('a').text
except:
item['author'] = None
# 将出版社放回DDbook类的publish属性
item['publish'] = book.find_all('div', class_='publisher_info')[1].find('a').text
# 将书籍价格放回DDbook类的price属性
item['price'] = book.find('span', class_='price_r').text
# 将折扣放回DDbook的discount属性
item['discount'] = book.find('span', class_='price_s').text
# 将折扣价放回DDbook的dis_price属性
item['dis_price'] = book.find('span', class_='price_n').text
# 将评价数量放回到DDbook的rating_num属性
item['rating_num'] = book.find('div', class_='star').find('a').text
# yield语句把item传递给引擎
yield item
4. 存储文件
采用CSV格式进行存储,在settings.py中输入如下代码:
FEED_URI = '%(name)s.csv'
FEED_FORMAT = 'CSV'
FEED_EXPORT_ENCODING = 'ansi'
需要注意:在最新的scrapy版本2.1.0不支持这种方式。需要降级到1.8.0版本才能存储进csv文件中。
5. 修改设置
在settings.py文件里添加请求头,以及把ROBOTSTXT_OBEY=True改成ROBOTSTXT_OBEY=False。
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36'}
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
同时修改一下下载延迟时间,调整到0.5秒。
# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 0.5
6. 运行scrapy
在与scrapy.cfg文件同级中,建立main.py文件。输入以下代码,接着运行即可。
from scrapy import cmdline
cmdline.execute(['scrapy','crawl','DDbook'])