music unfamous original game design efficient software wtf
life ui algorithm fix programming

Scrapy1.1.1 爬虫试验--爬取酷壳

作者:trinity  Python    2016-7-25  标签:  programming 

当然是简单的爬虫,做这个工作最合适的是 Python 了。

    1.给定初始地址,下载页面

    2.从页面中解析出内容页面链接(列表A),解析出下一页链接(地址B)

    3.循环下载列表A链接地址文件,解析出需要的条目(字典C)。保存(标注1)

    4.地址B存在,下载地址B文件,跳转到步骤2

    5.地址B不存在,结束。

    (标注1:可以保存到文件,csv,各种(no)sql数据库,比较理想的是保存到 elasticsearch)

中间会涉及到 https,cookies,gzip,登录,验证码这些细节,碰到再说吧。找个简单的网站试试。www.coolshell.cn 这个博客不错。本来用 Requests 和 lxml 来完成大部分的工作,怎么架构,怎么定义接口,想想 Scrapy 应该会节约我不少时间,不是说好的“人生苦短,我用 Python”么。

pip install scrapy

不出意外,会碰到 lxml 的编译错误.安装依赖:

sudo apt install openssl
sudo apt install libssl-dev
sudo apt install python-openssl
sudo apt install libxslt1-dev

命令行输入 scrapy 显示帮助。scrapy 是个蜘蛛框架,就像MFC之于Windows, .Net 之于 C#

cd myspiders
scrapy startproject pin
cd pin
scrapy genspider pinruan coolshell.com

就产生了一只名为 pinruan 的爬虫,它怎么爬,还需要进一步指挥。以上几条命令类似于 VisualStudio 自动生成代码的 Wizard,生成了一批文件:

    scrapy.cfg -- scrapy 在这个project的配置文件

    pin/items.py -- 定义要抓取的数据条目,对应上文 字典C。

    pin/pipelines.py -- 处理 字典C 的自定义方式

    pin/settings.py -- 设置文件,关于这个爬虫所有要设置的条目

    pin/spiders/pinruan.py -- 爬虫文件,怎么爬就在这里指挥

先来修改 items.py

import scrapy
class BlogItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()		# 标题
    content=scrapy.Field()		# 内容
    catalog=scrapy.Field()		# 类别
    tags =scrapy.Field()		#
    time=scrapy.Field()			# 日期
    author=scrapy.Field()
先简单着来,保存为 json 文件,修改 pipelines.py
import json
import codecs

class PinPipeline(object):
	def __init__(self):
		self.file=codecs.open('items.json','wb',encoding='utf-8')
	def process_item(self, item, spider):
		line=json.dumps(dict(item),ensure_ascii=False) + "\n"
		self.file.write(line)
		return item
	def close_spider(self,spider):
		self.file.close()
注意,这里用 codecs 库来打开,在 json.dumps 中指定 ensure_ascii=False ,否则一般的 utf-8 编码的网页不能正常保存。


然后 settings.py 中启用 PinPipeline 

ITEM_PIPELINES = {
    'pin.pipelines.PinPipeline': 300,
}
到了指挥爬取的时候了,好在整个逻辑还是比较简单的。编辑 pinruan.py
import scrapy
from scrapy.selector import HtmlXPathSelector
from pin.items import BlogItem 

class PinruanSpider(scrapy.Spider):
    name = "pinruan"
    allowed_domains = ["coolshell.cn"]
    start_urls = (
        'http://coolshell.cn',
    )

    def parse_content(self, response):
    	blogs = response.xpath('//div[@class="post"]')
    	for blog in blogs:
    		item = BlogItem()
    		item['title']=blog.xpath('h2/text()').extract_first()
    		item['time']=blog.xpath('div/span[@class="date"]/text()').extract_first()
    		item['author']=blog.xpath('div/span/a[@rel="author"]/text()').extract_first()
    		item['content']=blog.xpath('div[@class="content"]/node()').extract()
    		item['catalog']=blog.xpath('div/span/a[@rel="category tag"]/text()').extract()
    		item['tags']=blog.xpath('div/span/a[@rel="tag"]/text()').extract()
    		yield item
    def parse(self, response):
    	#request blog content
    	for url in response.xpath("//a[@class='title']"):
    		post_url = url.xpath('@href').extract_first()
    		#print post_url
    		yield scrapy.Request(post_url,callback=self.parse_content)
    	# request next page
    	pages = response.xpath('//div[@class="wp-pagenavi"]/span[@class="current"]/following-sibling::*')
    	if(len(pages) > 0): next_page_url = pages.xpath('@href').extract_first()
    		yield scrapy.Request(next_page_url,callback=self.parse)
    		print next_page_url
回到命令行
cd ~/myspiders/pin
scrapy crawl pinruan (--nolog)
开始爬取。这个爬虫没有下载文章使用的图片,60多页的博客下载完毕还不到10M,博客空间要那么大干嘛?