scrapy初探:写一个简单的爬虫
outline:
0 简介
1 工程的建立:
2 简单的爬虫
3 执行爬虫
4 文件下载
5 总结
0 简介
scrapy是一个爬虫框架。
该框架能够让我们集中在爬虫的核心处理上。但是,框架带来的缺点就是不够灵活。
1 工程的建立
前提:已经安装好python以及scrapy
在cmd中,进入相应的目录,使用命令:
scrapy startproject spider_name
得到目录如下:
spider_name/
scrapy.cfg
spider_name/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
...
items.py:定义爬虫中的所有item。
spiders目录:要添加的代码目录。
scrapy.cfg:爬虫的配置文件。
pipelines.py:定义了爬虫的pipeline。
tips: Item是保存爬取的数据的一个容器;他的使用方法类似于python的字典。引用块内容
2 简单的爬虫
该小节写一个简单的爬虫demo。
<1> 在spiders目录里面添加一个py文件,当前定位myspider.py。这个文件就是当前爬虫的代码文件。
<2> 定义自己的Item,该Item继承自类scrapy.Item。在其中定义要保存的字段,该字段可以用scrapy.Field()初始化。该Item加载items.py中,当然也不是强制。
class MyItem(scrapy.Item):
url = scrapy.Field()
name = scrapy.Field()
代码中,定义了MyItem,其中要保存两个字段,一个是爬取的网页的URL,一个是爬取的网页的名字。
<3> 爬虫的主体,是要定义一个CrawlSpider的子类。这个类中定义了爬虫的动作。该类的主要属性有:
name: 定义了爬虫的名称,一个工程内,各个爬虫的名称不要重复。
allow_domains:定义了爬虫爬取网页允许的域名,是一个列表。
start_url:定义爬虫开始的URL,为一个列表。
rules:定义了爬虫遍历的链接的规则,为一个Rule类的列表。
在Rule类中,通常需要显示指定几个常用的参数:
LinkExtractor对象:接受allow,deny等参数,参数为正则表达式,表示要继续爬去的网页链接和拒绝的网页链接。
回调函数:使用字符串的形式传入回调函数的名称。不能使用parse作为回调函数,因为这个函数不能被重载。
follow参数:bool值,表示是否遍历。如果没有回调函数,该值默认为True。
另外两个中要的函数:
1> rules中的回调函数。
2 > parse_start_url: 该函数是需要改写的父类的函数。定义了在在start_url中的动作。
整个demo的代码如下:
# -*- coding -*-
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from scrapy.selector import Selector
from spider.items import MyItem
class MySpider(CrawlSpider):
name = 'MySpider'
allow_domains = ['douban.com']
start_urls = ['https://xxxxx.xxxxxx.com/chart/']
rules = [Rule(LinkExtractor(allow=[r'https://xxxxx.xxxxxx.com/subject/\d+/?$']), 'parse_it', follow=True)]
def parse_it(self, response):
myItem = MyItem()
myItem['url']= response.url
myItem['name'] = response.xpath("//title/text()").extract()
return myItem
def parse_start_url(self, response):
pass
这个demo中,只是简单的爬取网页的标题。在实际中,我们可以做更多的操作,比如统计网站中的数据,将网站中的图片下载下来等等。这些操作可以加载parse_start_url和parse_it这两个函数中。
3 执行爬虫
通过执行如下命令执行爬虫:
scrapy crawl MySpider
执行该命令需要进入到爬虫的目录中,第三个参数即为代码中定义的爬虫的名称。也可以将爬取的数据保存在文件中:
scrapy crawl MySpider -o items.json
每次要在命令行中切来切去的很烦,我们可以使用scrapy的cmdline, 在scrapy.cfg的同级目录下加入一个一个main.py如下,之后每次在pycharm中执行该脚本即可运行脚本。
# -*- coding:utf-8 -*-
from scrapy import cmdline
cmdline.execute("scrapy crawl MySpider".split())
下面为爬取的json数据中的一部分:
[
[
{“url”: “https://xxxxx.xxxxxx.com/subject/26844922/“, “name”: [“\n \u6770\u51fa\u516c\u6c11\n”]},
{“url”: “https://xxxxx.xxxxxx.com/subject/26279289/“, “name”: [“\n \u6012\n”]},
{“url”: “https://xxxxx.xxxxxx.com/subject/25765735/“, “name”: [“\n \u91d1\u521a\u72fc3\uff1a\u6b8a\u6b7b\u4e00\u6218\n”]},
{“url”: “https://xxxxx.xxxxxx.com/subject/6873143/“, “name”: [“\n \u4e00\u6761\u72d7\u7684\u4f7f\u547d\n”]},
……
]
可以看到,爬取的内容即为Item中定义的内容。
有些网站可能使用了反爬虫机制,在这里,有一个简单的解决方法就是设置代理。在setting.py中加入设置如下:
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5'
4 文件下载
文件下载可以使用PIPELINE,常用的PIPELINE有FILESPIPELINE和IMAGEPIPELINE。在这个小节,以FILESPIPELINE来简单记录用法。
**一个在setting.py中,pipeline需要有两步工作:
① 在配置项中**pipeine。
ITEM_PIPELINES = {
'spider.pipelines.MyPipeline': 3,
}
后面的数字是顺序,定义在1~1000内。
② 定义一个合法的目录。
FILES_STORE = '/pic'
这两个步骤都是必须的,一个没有配置好,就不会启动PIPELINE。
之后的工作,也就是最重要的工作就是定义PIPELINE类了。
在pipelines.py中定义自己的pipeline类,继承自类FILESPIPELINE。
在类中,主要需要实现的函数有两个。
process_item:每个item传递到pipeline中执行的操作。
item_completed:内容下载完成之后执行的操作,我们可以在这里执行重命名之类的动作。当然这个函数不是必须的,如果没有重命名的动作,下载下来的文件是以一个哈希码命名的。
下面是一个简单的demo:
class MyPipeline(FilesPipeline):
def process_item(self, item, spider):
for url in item["file_urls"]:
yield Request(url)
def item_completed(self, results, item, info):
pass
这里的file_urls需要在MySpider类中得到。为了方便的得到url,可以使用scrapy的选择器Selector。如下面的代码得到所有img标签中src字段带有.jpg的内容。
myItem['file_urls'] = Selector(text=response.body).xpath("//img[contains(@src, '.jpg')]/@src").extract()
有的时候,我们下载不下来内容,观察输出,会发现403错误。这是因为scrapy默认是遵循roberts协议的。在settings.py中加入以下配置,表示不遵守roberts协议。
ROBOTSTXT_OBEY = False
6 总结
scrapy是一个很方便快捷的爬虫框架,使用起来,只用关注url的正则表达式和一些关键动作代码就可以实现一个完整的爬虫。但是也牺牲了一定的灵活性。
上一篇: JavaWeb测试,反射,注解
下一篇: 国内某金融技术公司笔试题2020年