解析所有文章及提取下一页
# -*- coding: utf-8 -*-
import scrapy
import re
from scrapy.http import Request
from urllib import parse
# 提取字符串中的数字
def get_nums(str):
match_re = re.match(".*(\d+).*", str)
if match_re:
nums = int(match_re.group(1))
else:
nums = 0
return nums
class JobboleSpider(scrapy.Spider):
name = 'jobbole'
allowed_domains = ['blog.jobbole.com']
start_urls = ['http://blog.jobbole.com/all-posts/']
def parse(self, response):
"""
1.获取文章列表中的文章url并交给scrapy下载解析
2.获取下一页的url并交给scrapy进行下载,下载后再交给parse
"""
# 解析文章所有url并交给scrapy下载后解析
post_nodes = response.css("#archive .floated-thumb .post-thumb a")
for post_node in post_nodes:
image_url = post_node.css("img::attr(src)").extract_first("")
post_url = post_node.css("::attr(href)").extract_first("")
print(post_url) # 文章url
# parse.urljoin(response.url, post_url)表示有绝对域名就直接使用,相对域名就拼接主域名
yield Request(url=parse.urljoin(response.url, post_url), meta={"front_image_url": image_url}, callback=self.parse_detail)
# 提取下一页并交给scrapy进行下载
next_urls = response.css(".next.page-numbers::attr(href)").extract_first()
if next_urls:
yield Request(url=parse.urljoin(response.url, next_urls), callback=self.parse)
# 提取文章的具体字段
def parse_detail(self, response):
front_image_url = response.meta.get("front_image_url", "") # 获取response中的front_image_url 图片
title = response.css('.entry-header h1::text').extract_first
create_date = response.css('.entry-meta-hide-on-mobile::text').extract()[0].strip().replace("·", "")
praise_nums = response.css('.vote-post-up h10::text').extract()[0]
fav_str = response.css('.bookmark-btn::text').extract()[0]
fav_nums = get_nums(fav_str)
comment_str = response.css('a[href="#article-comment"] span::text').extract()[0]
comment_nums = get_nums(comment_str)
# content = response.css('div.entry').extract()[0]
tags = response.css('p.entry-meta-hide-on-mobile a::text').extract()[0]
pass
如果yield Request 不执行,需要加dont_filter=True
# parse.urljoin(response.url, post_url)表示有绝对域名就直接使用,相对域名就拼接主域名
yield Request(url=parse.urljoin(response.url, post_url), callback=self.parse_detail, dont_filter=True)
items设计
- 在setting中将以下代码的注释去掉
ITEM_PIPELINES = { 'ArticleSpider.pipelines.ArticlespiderPipeline': 300, } - 在item.py 中写下item项
# -*- coding: utf-8 -*-
import scrapy
class ArticlespiderItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
pass
class JobBoleArticleItem(scrapy.Item):
# 标题
title = scrapy.Field()
# 日期
create_date = scrapy.Field()
# url
url = scrapy.Field()
url_object_id = scrapy.Field() # url是变长 可以md5定常加密保存
# 标题图
front_image_url = scrapy.Field()
# 标题图地址
front_image_path = scrapy.Field()
# 点赞数
praise_nums = scrapy.Field()
# 喜爱数
fav_nums = scrapy.Field()
# 评论数
comment_nums = scrapy.Field()
# 文章内容
content = scrapy.Field()
# 标签
tags = scrapy.Field()
- 在jobbloe.py解析函数中写入
from ArticleSpider.items import JobBoleArticleItem, ArticleItemLoader
article_item["title"] = title
article_item["create_date"] = create_date
article_item["front_image_url"] = front_image_url
article_item["praise_nums"] = praise_nums
article_item["fav_nums"] = fav_nums
article_item["comment_nums"] = comment_nums
article_item["content"] = content
article_item["tags"] = tags
article_item["url"] = response.url
yield article_item
- 设置图片存放路径
首先在项目目录下,与spider目录同级的地方新建images文件夹。再次在setting中配置如下代码
import os
ITEM_PIPELINES = {
'ArticleSpider.pipelines.ArticlespiderPipeline': 300,
'scrapy.pipelines.images.ImagesPipeline': 1,
}
IMAGES_URLS_FIELD = "front_image_url"
project_dir = os.path.abspath(os.path.dirname(__file__))
IMAGES_STORE = os.path.join(project_dir, 'images')
如果报缺少"PIL"库,该库与图片相关请安装 pillow。 如果报valueError:Missing scheme in request url:h错,原因是将图片下载的item会被当作数组处理,所以修改jobbloe.py下的
article_item["front_image_url"] = front_image_url
# 修改为
article_item["front_image_url"] = [front_image_url]
- 重载imagespipeline
首先在pipelines.py中写入
# -*- coding: utf-8 -*-
from scrapy.pipelines.images import ImagesPipeline
class ArticlespiderPipeline(object):
def process_item(self, item, spider):
return item
class ArticleImagesPipeline(ImagesPipeline):
# 重载文件获取实际下载地址
def item_completed(self, result, item, info):
for ok, value in result:
image_file_path = value["path"]
item["front_image_path"] = image_file_path
return item
其次在setting.py中设置
ITEM_PIPELINES = {
'ArticleSpider.pipelines.ArticlespiderPipeline': 300,
'ArticleSpider.pipelines.ArticleImagesPipeline': 1,
# 'scrapy.pipelines.images.ImagesPipeline': 1,
}
# 将front_image_url字段图片保存到本地的配置
IMAGES_URLS_FIELD = "front_image_url"
project_dir = os.path.abspath(os.path.dirname(__file__))
IMAGES_STORE = os.path.join(project_dir, 'images')
新建utils文件夹新建common.py文件
# _*_ coding: utf-8 _*_
import hashlib
def get_md5(url):
if isinstance(url, str):
url= url.encode("utf-8")
m = hashlib.md5()
m.update(url)
return m.hexdigest()
if __name__ == "__main__":
print(get_md5("https://www.baidu.com"))
在jobbloe.py中添加
from ArticleSpider.utils.common import get_md5
article_item["front_image_path"] = get_md5(response.url)