想了想决定,把想要爬的网站都汇总起来,一方面是这样更方便清晰,另一方面也是督促自己每天都编程。
完成后会顺带写上关键点和一些心得。
先定个小目标,爬他100个
网易云音乐的音乐
花瓣采集的图片
instagram的图片
直接爬取
最简单的爬取方式大概就是直接爬取了,单纯使用request方法就可以拿到目标信息,不需要添加头文件也不需要进行模拟登录,甚至动态加载的部分都可以通过instagram的更多的herf进行跳转从而避开抓包步骤。但是考虑到效率问题,只适用于较少链接的爬取,发帖数应当少于200。
示例代码
维基百科编辑ip分布地图
微博情绪地图
拉勾网实习搜索
matplotlib示例代码下载
项目说明
采用scrapy框架可以快速下载,使用FilesPipeline(可以看作是特殊的下载器,通过item的一个特殊字段将目标文件的url传递给它,就可以自动下载,并将下载结果信息存入item的另一个字段,方便查阅)。
|
FilesPipeline |
ImagesPipeline |
导入路径 |
scrapy.pipelines.files.FilesPipeline |
secrapy.pipeline.images.ImagesPipeline |
Item字段 |
file_urls,files |
image_urls,images |
下载目录 |
FILE_STORE |
IMAGES_STORE |
页面分析
- 使用scrapy shell来下载目标界面,然后调用view函数在浏览器查看。
- 发现例子页面链接,使用LinkExtractor提取所有例子页面链接。
- 分析例子页面,使用fetch函数进入下载第一个例子页面,调用view函数查看。
- 分析下载地址,完成。
编码实现
- 创建Scrapy项目。
- 在配置文件启用FilesPipeline,指定下载目录。
- 实现Item。
- 实现Spider。
下载完成后,发现文件名为一串数字,这些数字是下载文件url的sha1散列值。这种命名方式可以防止重名文件相互覆盖,但并不直观。
实现一个FilesPipeline的子类,覆写file_path方法来实现期望的文件命名规则。
1 2 3 4 5 6 7 8 9
| from scrapy.pipelines.files import FilesPipeline from urllib.parse import urlparse from os.path import basename, dirname, join class MatpoltlibexamplePipeline(FilesPipeline): def file_path(self, request, response=None, info=None): path=urlparse(request.url).path return join(basename(dirname(path)), basename(path))
|
杭电图书馆图书
豆瓣阅读热门标签
项目说明
爬取豆瓣阅读所有热门标签下的书籍名称,评分和评价人数。
这个项目的起因是有朋友需要对豆瓣阅读的信息进行数据挖掘,刚好自己没什么事情就随手写了,具体实现并不困难。
值得学习
utf8格式存储json
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| class DoubannovelPipeline(object): def __init__(self): self.file = codecs.open('douban_novel_utf8.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 spider_closed(self, spider): self.file.close()
|
随机选择代理
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class DoubannovelSpiderMiddleware(HttpProxyMiddleware): def __init__(self, auth_encoding='latin-1', proxy_list_file=None): if not proxy_list_file: raise NotConfigured self.auth_encoding = auth_encoding self.proxies = defaultdict(list) with open(proxy_list_file) as f: proxy_list = json.load(f) for proxy in proxy_list: scheme = proxy['proxy_scheme'] url = proxy['proxy'] self.proxies[scheme].append(self._get_proxy(url,scheme)) @classmethod def from_crawler(cls, crawler): auth_encoding = crawler.settings.get('HTTPPROXY_AUTH_ENCODING', 'latin-1') proxy_list_file = crawler.settings.get('HTTPPROXY_PROXY_LIST_FILE') return cls(auth_encoding, proxy_list_file) def spider_opened(self, spider): spider.logger.info('Spider opened: %s' % spider.name) def _set_proxy(self, request, scheme): creds, proxy = random.choice(self.proxies[scheme]) request.meta['proxy'] = proxy if creds: request.headers['Proxy-Authorization'] = b'Basic' + creds
|
不足之处
- 数据量非常大,大概有10w多条,由于使用没有进行分布式处理也没有挂在服务器上跑,导致电脑被占用了一个下午,心痛。
- 随机代理无法自动删除无效代理,无法重新下载失败链接,导致失败链接丢失,影响下载质量。
- 豆瓣页面明明写的20本书!但是部分页面实际只有19本!骗子!过分!!哼!!!