写在前面
最近在学习 Python 的语法, 刷刷 LeetCode 什么的. 熟悉之后, 就想着写一个爬虫实际运用一下.
如何入门 Python 爬虫? - 高野良的回答 - 知乎 https://www.zhihu.com/question/20899988/answer/58388759
知乎了一下, 然后看了 http://scrapy-chs.readthedocs.io/zh_CN/1.0/index.html 的文档 , 就开始动手了.
那么爬什么呢
当时就想着写一个根据目录来下载 github 仓库文件的 spider. 因为以前下载 github 仓库的时候要么只能根据 git 地址 clone 整个 repo, 要么只能通过 octoTree 或者 insightio 下载单个文件, 然而经常会有需要下载单个或者多个目录的情况, 所以就想着写一个根据目录来下载 github 上文件的爬虫.
开始
要开始, 当然是推荐看官方的入门教程 http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/tutorial.html 了.
这里简单描述下步骤:
##1. 创建项目
scrapy startproject scrapy_github_dir
##2. 创建爬虫
scrapy genspider app github.com
- ##3. 写逻辑或者进行设置等等
- ##4. 运行爬虫, 爬取路径是 github 上的目录或者文件
- scrapy crawl app -a urls = https://github.com/ditclear/BindingListAdapter/tree/917e254f527d101e3f583c38739a61f3bcffbc11/library-kotlin
主要的代码都在 https://github.com/ditclear/scrapy_github_dir/blob/6a0bd6757935440a36ce933326c810417c1f461c/scrapy_github_dir/spiders/app.py 里, 当运行
scrapy genspider app github.com
时会主动帮你生成它
- import scrapy
- from ..items import ScrapyGithubDirItem
- class AppSpider(scrapy.Spider):
- name = 'app'
- allowed_domains = ['github.com']
- content_domains = 'https://github.com/'
- start_urls = []
- def __init__(self, urls=None, *args, **kwargs):
- super(AppSpider, self).__init__(*args, **kwargs)
- self.start_urls = urls.split(',')
- // 运行 scrapy crawl xx 后, 处理 response
- def parse(self, response):
- raw_url = response.CSS('a#raw-url').xpath('@href').extract_first()
- if raw_url:
- href = self.content_domains+raw_url
- print("scrapy from href -->", href)
- yield scrapy.Request(href, callback=self.parse_link)
- else:
- for link in response.selector.xpath('//a[@class="js-navigation-open"]/@href').extract()[1:]:
- href = self.content_domains+link
- yield scrapy.Request(href, callback=self.parse)
- def parse_link(self, response):
- responseStr = str(response).strip()
- url = responseStr.strip()[5:len(responseStr)-1]
- print('download from url -->', url)
- item = ScrapyGithubDirItem()
- item['file_urls'] = [url]
- return item
当运行 scrapy crawl xx 后, 会在
parse(self, response)
方法处理 response.
处理 response, 简单理解来就是通过 css 选择器和 xpath 来找到你想要的内容, 比如 text/img/href 等等, 获取到想要的内容后, 保存到文件, 数据库, 期间掺杂着一些 scarpy 的配置.
通过分析网页源文件:
可以看到单个文件的下载链接在 id 为 raw-url 的 a 标签中, 所以我们需要找到这个标签然后获取到想要的链接.
raw_url = response.css('a#raw-url').xpath('@href').extract()
这里的意思是通过 css 选择器找到 id 为 raw-url 的 a 标签, 然后获取到 a 标签的 href 参数, 最后提取出来以列表的形式返回.
如果没有返回那么则表示当前 request 的 url 不是具体的某个文件, 而是一个目录.
如果当前 url 是目录
分析一下目录的 response 的结构, 通过 css 选择器和 xpath 继续找到其下一级的文件
同样的, 找到这个地址
response.selector.xpath('//a[@class="js-navigation-open"]/@href').extract()
需要注意的是返回的列表中, 第一个索引的值指向的是上一级目录, 所以需要将其排除掉. 接着递归调用当前的 parse 方法, 直到爬取到文件为止.
- if raw_url:
- // 爬取具体的文件
- yield scrapy.Request(href, callback=self.parse_link)
- else:
- // 如果是目录, 递归直到爬取到文件为止
- for link in response.selector.xpath('//a[@class="js-navigation-open"]/@href').extract()[1:]:
- yield scrapy.Request(href, callback=self.parse)
代码不多, 顺利的话半天就能成功.
写在最后
回顾一下, 能发现没怎么就已经写好了. 而爬虫简单看来就是通过 css 选择器, xpath 或者正则找到需要的数据, 然后进行想要的处理, 期间夹杂着递归的逻辑和算法, 当然这只是初见 scrapy, 不过已经能发现 Python 以及 Scrapy 的强大了.
github 地址: https://github.com/ditclear/scrapy_github_dir
参考资料:
http://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/selectors.html
来源: https://juejin.im/post/5b222e23e51d4558834645ef