原先用的是 selenium(后面有时间再写), 这是第一次使用 scrapy 这个爬虫框架, 所以记录一下这个心路历程, 制作简单的爬虫其实不难, 你需要的一般数据都可以爬取到.
下面是我的目录, 除了 main.py 以外, 都是代码自动生成的 :).
各个目录作用:
1,sina 是我自己创建的文件夹用来盛放整个项目的, 随便起名字.
2, 第一个 sinaSpeder 文件夹内, 有一个 scrapy.cfg 配置文件和 sinaSpeder 的文件夹
scrapy.cfg: 配置文件, 不需要更改
sinaSpeder 文件夹
3, 第二个 sinaSpeder 文件夹
init.py : 特定文件, 指明二级 first_spider 目录为一个 python 模块
item.py: 定义需要的 item 类 [实验中需要用到]
pipelines.py: 管道文件, 传入 item.py 中的 item 类, 清理数据, 保存或入库
settings.py: 设置文件, 例如设置用户代理和初始下载延迟
spiders 目录
4,spiders
init.py : 特定文件, 指明二级 first_spider 目录为一个 python 模块
sina.py: 盛放自定义爬虫的文件, 负责获取 html 的数据和传入 pipline 管道中进行数据存放等
废话不多说, 开练~~
第一步创建爬虫项目:
- scrapy startproject sinaSpeder(项目名)
- (用命令创建主要是可以自动生成一个包含默认文件的目录)
第二步输入网址:
scrapy genspider sina "sina.com.cn" (这个名字是 spiders 里面的名字, 后面的链接是要爬取的链接)
第三步修改代码: 参考自:
items.py 写入:
- # -*- coding: utf-8 -*-
- # Define here the models for your scraped items
- #
- # See documentation in:
- # https://doc.scrapy.org/en/latest/topics/items.html
- import scrapy
- import sys
- # reload(sys)
- # sys.setdefaultencoding("utf-8")
- class SinaspederItem(scrapy.Item):
- # 大类的标题和 url
- parentTitle = scrapy.Field()
- parentUrls = scrapy.Field()
- # 小类的标题和子 url
- subTitle = scrapy.Field()
- subUrls = scrapy.Field()
- # 小类目录存储路径
- subFilename = scrapy.Field()
- # 小类下的子链接
- sonUrls = scrapy.Field()
- # 文章标题和内容
- head = scrapy.Field()
- content = scrapy.Field()
- View Code
sina.py 写入:
- # -*- coding: utf-8 -*-
- import scrapy
- import os
- from sinaSpeder.items import SinaspederItem
- import sys
- # reload(sys)
- # sys.setdefaultencoding("utf-8")
- class SinaSpider(scrapy.Spider):
- name = "sina"
- allowed_domains = ["sina.com.cn"]
- start_urls = ['http://news.sina.com.cn/guide/']
- def parse(self, response):
- items = []
- # 所有大类的 url 和 标题
- parentUrls = response.xpath('//div[@id="tab01"]/div/h3/a/@href').extract()
- parentTitle = response.xpath('//div[@id="tab01"]/div/h3/a/text()').extract()
- # 所有小类的 ur 和 标题
- subUrls = response.xpath('//div[@id="tab01"]/div/ul/li/a/@href').extract()
- subTitle = response.xpath('//div[@id="tab01"]/div/ul/li/a/text()').extract()
- # 爬取所有大类
- for i in range(0, len(parentTitle)):
- # 指定大类目录的路径和目录名
- parentFilename = "./Data/" + parentTitle[i]
- # 如果目录不存在, 则创建目录
- if (not os.path.exists(parentFilename)):
- os.makedirs(parentFilename)
- # 爬取所有小类
- for j in range(0, len(subUrls)):
- item = SinaspederItem()
- # 保存大类的 title 和 urls
- item['parentTitle'] = parentTitle[i]
- item['parentUrls'] = parentUrls[i]
- # 检查小类的 url 是否以同类别大类 url 开头, 如果是返回 True (sports.sina.com.cn 和 sports.sina.com.cn/nba)
- if_belong = subUrls[j].startswith(item['parentUrls'])
- # 如果属于本大类, 将存储目录放在本大类目录下
- if (if_belong):
- subFilename = parentFilename + '/' + subTitle[j]
- # 如果目录不存在, 则创建目录
- if (not os.path.exists(subFilename)):
- os.makedirs(subFilename)
- # 存储 小类 url,title 和 filename 字段数据
- item['subUrls'] = subUrls[j]
- item['subTitle'] = subTitle[j]
- item['subFilename'] = subFilename
- items.append(item)
- # 发送每个小类 url 的 Request 请求, 得到 Response 连同包含 meta 数据 一同交给回调函数 second_parse 方法处理
- for item in items:
- yield scrapy.Request(url=item['subUrls'], meta={'meta_1': item}, callback=self.second_parse)
- # 对于返回的小类的 url, 再进行递归请求
- def second_parse(self, response):
- # 提取每次 Response 的 meta 数据
- meta_1 = response.meta['meta_1']
- # 取出小类里所有子链接
- sonUrls = response.xpath('//a/@href').extract()
- items = []
- for i in range(0, len(sonUrls)):
- # 检查每个链接是否以大类 url 开头, 以. shtml 结尾, 如果是返回 True
- if_belong = sonUrls[i].endswith('.shtml') and sonUrls[i].startswith(meta_1['parentUrls'])
- # 如果属于本大类, 获取字段值放在同一个 item 下便于传输
- if (if_belong):
- item = SinaspederItem()
- item['parentTitle'] = meta_1['parentTitle']
- item['parentUrls'] = meta_1['parentUrls']
- item['subUrls'] = meta_1['subUrls']
- item['subTitle'] = meta_1['subTitle']
- item['subFilename'] = meta_1['subFilename']
- item['sonUrls'] = sonUrls[i]
- items.append(item)
- # 发送每个小类下子链接 url 的 Request 请求, 得到 Response 后连同包含 meta 数据 一同交给回调函数 detail_parse 方法处理
- for item in items:
- yield scrapy.Request(url=item['sonUrls'], meta={'meta_2': item}, callback=self.detail_parse)
- # 数据解析方法, 获取文章标题和内容
- def detail_parse(self, response):
- item = response.meta['meta_2']
- content = "" head = response.xpath('//h1[@id="main_title"]/text()')
- content_list = response.xpath('//div[@id="artibody"]/p/text()').extract()
- # 将 p 标签里的文本内容合并到一起
- for content_one in content_list:
- content += content_one
- item['head'] = head
- item['content'] = content
- yield item
- View Code
pipelines.py 写入:
- # -*- coding: utf-8 -*-
- from scrapy import signals
- import sys
- class SinaspederPipeline(object):
- def process_item(self, item, spider):
- sonUrls = item['sonUrls']
- # 文件名为子链接 url 中间部分, 并将 / 替换为 _, 保存为 .txt 格式
- filename = sonUrls[7:-6].replace('/','_')
- filename += ".txt"
- fp = open(item['subFilename']+'/'+filename, 'w')
- fp.write(item['content'])
- fp.close()
- return item
setting.py 写入:
- # 设置管道文件
- ITEM_PIPELINES = {
- 'sinaSpeder.pipelines.SinaspederPipeline': 300,
- }
main.py 写入:
- from scrapy import cmdline
- cmdline.execute("scrapy crawl sina".split())
运行有两种方法:
1, 这里创建了 main.py 文件, 所以可以直接运行这个文件.
2, 通过命令行
scrapy crawl sina (这个是进入...>sina>sinaSpeder 文件夹后运行的)
第四步:
运行开始后, 多出一个 data 文件夹, 这就是要爬取的东西
注: 问题总结
1, 我最初是运行下面这个, 发现报错, 后来试试 spiders 中的 sina.py 文件, 结果成功了
scrapy crawl sinaSpeder
2, 如果你建立的工程名字和我的不一样, 所有涉及项目名称的文件都要改过来, 少一个都会报错.
3, 爬虫运行有可能会被封 ip 使得无法再访问这个网站了! 这就需要使用反爬虫技术, 以后再讲.
参考:
- https://www.jianshu.com/p/fd443ad67c5b?utm_campaign
- https://www.cnblogs.com/xinyangsdut/p/7631163.html
来源: https://www.cnblogs.com/51python/p/10524690.html