使用Scrapy爬取伯乐在线的文章,将爬取的数据保存到MySQL数据库中。
使用Scrapy命令来创建项目。
我们先来分析一下整体的流程,我们想要获取,文章的图片,标题,发布的时间,详情页的链接,点赞数,收藏数,评论数。我们首先需要获取的是每一篇文章的详情页链接,图片地址,以及,下一页的地址。而后进入到文章的详情页,去获取文章的标题,发布日期,点赞数,评论数,收藏数,然后将这些数据保存到MySQL数据库中。OK!我们这样编写代码。
class BlogSpider(scrapy.Spider):
name = 'blog'
allowed_domains = ['blog.jobbole.com']
start_urls = ['http://blog.jobbole.com/all-posts/']
def parse(self, response):
item_list=response.xpath('//div[@class="post floated-thumb"]')
for item in item_list:
# 获取图片的链接
image=item.xpath('.//div[@class="post-thumb"]/a/img/@src').extract_first('')
# 获取详情页的链接
url=item.xpath('.//a[@class="archive-title"]/@href').extract_first('')
# 将详情页链接,以及图片链接传递给下一个方法
yield scrapy.Request(url=url,meta={'img':image},callback=self.get_detail_with_url)
# 获取下一页的链接
next_url=response.xpath('//a[@class="next page-numbers"]/@href').extract()
if len(next_url)!=0:
page_url=next_url[0]
yield scrapy.Request(url=page_url,callback=self.parse)
def get_detail_with_url(self,response):
# 接收图片的链接
img=response.meta['img']
print(img)
# 获取标题
title=response.xpath('//div[@class="entry-header"]/h1/text()').extract_first('')
print(title)
# 获取时间
date_time=response.xpath('//div[@class="entry-meta"]/p[@class="entry-meta-hide-on-mobile"]/text()').extract_first('').strip()
time=date_time.split('·')[0]
print(time)
# 详情页地址
detail_url=response.url
print(detail_url)
# 获取点赞数
dian_zan=response.xpath('//h10/text()').extract_first('')
print(dian_zan)
# 获取收藏数
book_mark=response.xpath('//span[@class=" btn-bluet-bigger href-style bookmark-btn register-user-only "]/text()').extract_first('')
# 对数字进行单独的取出
book_mark_array=book_mark.split(' ')
book_mark_num=0
if len(book_mark_array[1])!=0:
book_mark_num=int(book_mark_array[1])
print(book_mark_num)
# 获取评论数
comment=response.xpath('//a[@href="#article-comment"]/span/text()').extract_first('')
# 对数字进行单独的取出
comment_arrat=comment.split(' ')
comment_num=0
if len(comment_arrat[1])!=0:
comment_num=int(comment_arrat[1])
print(comment_num)
print('------------------------------------------------------')
item=JobboleItem()
item['img']=img
item['title']=title
item['date_time']=time
item['detail_url']=detail_url
item['dian_zan']=dian_zan
item['book_mark']=book_mark_num
item['comment']=comment_num
yield item
class JobboleItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
img=scrapy.Field()
title=scrapy.Field()
date_time=scrapy.Field()
detail_url=scrapy.Field()
dian_zan=scrapy.Field()
book_mark=scrapy.Field()
comment=scrapy.Field()
pass
import pymysql
class JobbolePipeline(object):
#连接数据库
def __init__(self):
self.connect=pymysql.connect(host='localhost',user='root',password='123456',db='jobbole',port=3306)
self.cursor=self.connect.cursor()
def process_item(self, item, spider):
#往数据库里面写入数据
self.cursor.execute('insert into blog(img,title,detail_url,time,dian_zan,book_mark,comment)VALUES ("{}","{}","{}","{}","{}","{}","{}")'
.format(item['img'],item['title'],item['detail_url'],item['date_time'],item['dian_zan'],item['book_mark'],item['comment']))
self.connect.commit()
return item
def close_spider(self,spider):
self.cursor.close()
self.connect.close()
BOT_NAME = 'jobbole'
SPIDER_MODULES = ['jobbole.spiders']
NEWSPIDER_MODULE = 'jobbole.spiders'
ROBOTSTXT_OBEY = False
ITEM_PIPELINES = {
'jobbole.pipelines.JobbolePipeline': 300,
}
输入命令:scrapy crawl blog,打开数据库,刷新一下。
这样便算是完成了。但是我们可以看到,在blog.py中取出数据我们显得非常的麻烦,我们不仅要取出,然后剥离提取等等,感觉很混乱,所以,我们想要让这个代码顺序呈现的更加清晰,我们需要使用itemloader。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import scrapy
from ..items import JobboleItem
from ..items import ArticleItemLoader
class BlogSpider(scrapy.Spider):
name = 'blog'
allowed_domains = ['blog.jobbole.com']
start_urls = ['http://blog.jobbole.com/all-posts/']
def parse(self, response):
item_list=response.xpath('//div[@class="post floated-thumb"]')
for item in item_list:
# 获取图片的链接
image=item.xpath('.//div[@class="post-thumb"]/a/img/@src').extract_first('')
# 获取详情页的链接
url=item.xpath('.//a[@class="archive-title"]/@href').extract_first('')
# 将详情页链接,以及图片链接传递给下一个方法
yield scrapy.Request(url=url,meta={'img':image},callback=self.get_detail_with_url)
# 获取下一页的链接
next_url=response.xpath('//a[@class="next page-numbers"]/@href').extract()
if len(next_url)!=0:
page_url=next_url[0]
yield scrapy.Request(url=page_url,callback=self.parse)
def get_detail_with_url(self,response):
#创建itemLoader的实例化对象,需要传入两个参数
#第一个值为item的实例化对象
#第二个值为网页的源代码
item_loader=ArticleItemLoader(item=JobboleItem(),response=response)
#第一个值是设置field的名称
#第二个值是xpath路径
item_loader.add_xpath('title','//div[@class="entry-header"]/h1/text()')
item_loader.add_value('img',[response.meta['img']])
item_loader.add_xpath('date_time','//div[@class="entry-meta"]/p[@class="entry-meta-hide-on-mobile"]/text()')
item_loader.add_value('detail_url',response.url)
item_loader.add_xpath('dian_zan','//div[@class="post-adds"]//h10/text()')
item_loader.add_xpath('book_mark','//span[@class=" btn-bluet-bigger href-style bookmark-btn register-user-only "]/text()')
item_loader.add_xpath('comment','//a[@href="#article-comment"]/span/text()')
item=item_loader.load_item()
yield item
import scrapy
from scrapy.loader import ItemLoader
from scrapy.loader.processors import MapCompose,TakeFirst
import re
采用tmloader是数据分离数据的另外一种方式
def changeTitle(value):
value='标题:'+value
return value
def getNewTime(value):
newTime=value.split('·')[0].strip()
return newTime
def getNum(value):
pattern=re.compile(r'\d+')
result=re.findall(pattern,value)
if result:
return int(result[0])
else:
return 0
# 使用itemloader需要先继承Iitmloader
class ArticleItemLoader(ItemLoader):
#设置输出内容的类型,TakeFirst()获取所有数据的第一条数据
default_output_processor=TakeFirst()
class JobboleItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
img=scrapy.Field(
input_processor=MapCompose
)
title=scrapy.Field(
input_processor=MapCompose(changeTitle)
)
date_time=scrapy.Field(
input_processor=MapCompose(getNewTime)
)
detail_url=scrapy.Field()
dian_zan=scrapy.Field()
book_mark=scrapy.Field(
input_processor=MapCompose(getNum)
)
comment=scrapy.Field(
input_processor=MapCompose(getNum)
)
pass
输入命令:scrapy crawl blog ,按下回车键。进入数据库,点击刷新。
既然我们已经有了item,那为什么还有去使用itemloader呢,我们可以看到不管是使用xpath,都需要我们对数据进行正则的处理,会使我们的维护工作变得比较困难。使用itemloader是将提取和数据的过滤放到同一个函数当中,将数据的提取和数据的分离分成两个部分,使代码看起来更加的清晰,代码更加的整洁。也可以将数据的处理函数单独定义,也可以对一个数据使用多个处理的函数,这样的话对代码的重用有着非常好的实现。