- 首页
- 正文
用scrapy爬取自己博客的文章
用scrapy框架可以非常方便地爬取网站的内容,只需要简单写一些业务处理,同时配置好数据库还有一些参数配置就可以了,下次可以拿这个模板改一下业务来重复使用 我们爬取内容可以使用深度优先和广度优先,默认深度优先,这篇就先用scrapy爬取自己博客作为例子
爬取方法
- 深度优先
从起始页开始,选择一个链接,再选择一个链接不停地跟踪下去,处理完这条线路之后再转入下一个起始页,继续追踪链接
- 广度优先
会爬取起始页中的所有网页,然后在选择其中的一个网页,继续抓取在此网页中链接的所有网页
爬取思路
- 常规化
比如说要爬取一个博客的所有文章,可以根据是否还有分页来不停爬取博客的文章,而每一页又有很多文章,可以把这些文章做个循环爬取,其实所有网站都可以利用这种方法来爬取
- 特殊化
比如说要爬取拉勾网的所有的java职位,这时候就不能用分页的方法了,但可以利用正则来判断是否是java职位的网页,不停地爬取是java职位的网页
这两个种方法我们后面都会给出例子的,这里先用常规化的方法来爬取博客的内容
反爬措施
- 模拟浏览器,设置 header 头部信息
- 模拟人的行为,设置爬取的速度
- 模拟同时多人访问的行为,使用高匿代理IP不停地换ip
- 模拟浏览器,selenium+phantomjs来爬取 ajax 的网站
预备知识(不会详细写,可自行网上查找相关内容)
- scrapy shell
scrapy shell是一个交互式shell,您可以在这里调试你的抓取代码,而无需运行爬虫程序,在命令行里使用 scrapy shell
启动scrapy shell
- 正则表达式
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等
- CSS选择元素
比如我们想获取下图h2的元素,可以在代码或者scrapy shell中使用respose.css('h2')
- XPath选择元素
比如我们想获取下图h2的元素,可以在代码或者scrapy shell中使用respose.xpath('//*[@id="aside"]/header/hgroup/h2')
数据库基础
python 基础
创建项目
scrapy startproject scrapyBlog
cd scrapyBlog
scrapy genspider gvimblog-css 52gvim.com
项目结构
修改创建的爬虫类
- 进入到爬虫类的目录
cd scrapyBlog/scrapyBlog/spiders/
- 修改 gvimblog_css.py 的内容如下
# -*- coding: utf-8 -*-
import scrapy
class GvimblogCssSpider(scrapy.Spider):
name = 'gvimblog-css'
allowed_domains = ['52gvim.com']
start_urls = ['http://52gvim.com/']
def parse(self, response):
for item in response.css(".article"):
print '====='
print item.css("h1 > a::text").extract()
print '====='
- 部分变量和方法
name:标识爬虫。它在项目中必须是唯一的,也就是说,您不能为不同的Spider设置相同的名称。
allowed_domains:允许哪些域名能够爬取
start_urls:从网站的那个地址开始爬取,可以设置多个
parse():将被调用来处理为每个请求下载的响应的方法。 response参数是一个TextResponse保存页面内容的实例,并且具有更多有用的方法来处理它。
- parse 方法
for item in response.css(".article"):
print '====='
print item.css("h1 > a::text").extract()
print '====='
上面这些代码就是我们要处理的爬虫业务,当然,这里只是最简单的抓取了第一页的所有文章的标题,处理的逻辑是这样的:先用 css 方法获取所有的标题的元素,然后把这些元素做一个循环调用
完整例子
- 修改 scrapyBlog/scrapyBlog/spiders/gvimblog_css.py 文件的内容如下
# -*- coding: utf-8 -*-
import scrapy
import urlparse
from scrapy.http import Request
class GvimblogCssSpider(scrapy.Spider):
name = 'gvimblog-css'
allowed_domains = ['52gvim.com']
start_urls = ['http://52gvim.com/']
def parse(self, response):
# 把当前页的所有文章做一个循环
for item in response.css(".article"):
post_url = item.css("h1 > a::attr(href)").extract_first('')
# 把当前页的每一篇文章的地址传给 parse_detail 方法,在parse_detail获取特定内容
yield Request(url=urlparse.urljoin(response.url, post_url),
callback=self.parse_detail)
# 获取下一页的地址,不停地爬取下一页的内容
next_url = response.css(".page > a.next::attr(href)").extract_first('')
if next_url is not None:
yield Request(url=urlparse.urljoin(response.url, next_url),
callback=self.parse)
def parse_detail(self, response):
# 拿到每一篇文章里面的内容,然后交给 pipelines.py 处理
yield {
'title': response.css('.article h1::text').extract(),
'category': response.css('.article .icon-category a::text').extract(),
'tags': response.css('.article .icon-tags a::text').extract()
}
- 修改 scrapyBlog/scrapyBlog/pipelines.py 文件的内容如下
# -*- coding: utf-8 -*-
import json
import codecs
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
class JsonWithEncodingPipeline(object):
def __init__(self):
self.file = codecs.open('blog.json', 'w', 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()
- 修改 scrapyBlog/scrapyBlog/settings.py 文件,把ITEM_PIPELINES的注释去掉,并改为下面的内容
ITEM_PIPELINES = {
'scrapyBlog.pipelines.JsonWithEncodingPipeline': 300,
}
- 运行爬虫
scrapy crawl gvimblog-css
- 运行结果,可以看到在根目录生成了一个 blog.json 文件,内容如下