首页 > 技术文章 > 第三天,爬取伯乐在线文章代码,编写items.py,保存数据到本地json文件中

regit 2018-09-14 13:50 原文

 

 

 
 
一. 爬取http://blog.jobbole.com/all-posts/中的所有文章
 
 
1. 编写jobbole.py简单代码
import scrapy
from scrapy.http import Request
from urllib import parse
 
 
class JobboleSpider(scrapy.Spider):
    name = 'jobbole'
    allowed_domains = ['blog.jobbole.com']
    start_urls = ['http://blog.jobbole.com/all-posts/']
 
    def parse(self, response):
        # 提取当前页所有文章url地址并下载url内容,提取相关信息
        post_urls = response.css("#archive .floated-thumb .post-thumb a::attr(href)").extract()
        for post_url in post_urls:
            yield Request(url=parse.urljoin(response.url, post_url), callback=self.parse_detail)
        # 提取下一页url地址并下载
        next_url = response.css(".next.page-numbers::attr(href)").extract_first()
        if next_url:
            yield Request(url=parse.urljoin(response.url, next_url), callback=self.parse)
 
    def parse_detail(self, response):
        title = response.xpath('//div[@class="entry-header"]/h1/text()').extract_first()
        create_time = response.css("p.entry-meta-hide-on-mobile::text").extract()[0].strip().replace(" ·","")
        fav_nums = response.css(".bookmark-btn::text").re('.*?(\d+).*')
        # 收藏数可能为空,如果为空fav_nums[0]会抛异常
        if fav_nums:
            fav_nums = int(fav_nums[0])
        else:
            fav_nums = 0
        content = response.css("div.entry").extract()[0]

 

几个注意点
1)下载URL内容,可以使用scrapy内置模块Request:from scrapy.http import Request
2) url不包含域名时,比如/11032/,可使用parse函数: from urllib import parse,如下
>>> parse.urljoin("http://www.google.com/1/aaa.html","/2/bbbb.html")
'http://www.google.com/2/bbbb.html'
>>> parse.urljoin("http://www.google.com/1/aaa.html","http://www.google.com/ccc.html")
'http://www.google.com/ccc.html'
3) call_back后面的函数不能加()
yield Request(url=parse.urljoin(response.url, post_url), callback=self.parse_detail)
 
 
 
 
二. items中定义网页提取内容字段
 
1. 提取文章列表标题前的图片
 
相关代码如下
 
修改jobbole.py
 
 
2. items.py添加代码如下
 
 
3. jobbole.py->parse_detail中把ArticleItem实例化并赋值
 
 
4. 修改settings.py如下,pipeline主要用来存储数据,在settings.py同级目录创建images目录,用来存放文章标题图片
 
 
5. 运行main.py测试是否会保存图片
1)处理图片需要安装pillow库
pip install -i https://pypi.douban.com/simple pillow
 
2)需要修改jobbole.py中aiticle_item["front_images_url"]的数据类型为列表
 
 
 
6. 获取图片的保存位置
6.1 在pipelines.py中编写ArticleImagePipeline,它继承scrapy中的ImagesPipeline,重写item_completed()函数
 
6.2 修改settings.py
 
6.3 查看调试信息,其中的path即为图片的本地保存位置
 
6.4 完善ArticleImagePipeline,其中ok代表上面调试信息中的0=(bool)True,  value代表1={dict}...
注意最后一定要return item,因为这个item还要被后续的pipeline使用
 
 
 
7. 对URL进行md5编码
 
7.1 在settings.py同级目录中创建一个新的python package,用于存放常用的函数,比如名字为utils,然后在目录下创建python文件common.py
 
说明:
1) if __name__ == '__main__'通常用于测试函数自身代码是否正确
它的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。
2) hashlib只接收utf-8类型的编码,python中字符串默认是unicode编码,所以需要先编码为utf-8格式
3) isinstance()函数用于判断数据类型,这里是判断url是否为str类型,python3的str类型其实就是unicode类型,它已经没有unicode字样。
 
7.2 jobbole.py中添加
 
 
 
 
三. 保存item字段到json文件中
 
自定义json文件的导出
 
1. pipelines.py中编写保存item字段到json文件的类,
 
说明:
1)json.dumps()函数是将一个Python数据类型列表进行json格式的编码(可以这么理解,json.dumps()函数是将字典转化为字符串)
     json.loads()函数是将json格式数据转换为字典(可以这么理解,json.loads()函数是将字符串转化为字典)
2)ensure_ascii=False的作用是有中文时不会乱码
3)使用codecs来打开json文件是为了减少编码问题
 
 
2. 修改settings.py,把定义的JsonWithEncodingPipeline放在ITEM_PIPELINES中,然后运行main函数即可生成本地json文件
 
 
 
scrapy内置有生成json,csv等文件的机制,这里以生成json文件为例
 
1. 在pipelines.py中编写
 
2. 在settings.py中把原先自定义的JsonWithEncodingPipeline替换为JsonExporterPipeline
 
但是有问题,经测试只有一条数据
 
 
 

推荐阅读