一、爬虫简介
在爬取一些简单的(没有反爬机制的)静态网页时,一般采取的策略是:选中目标(所谓的url链接),观察结构(链接结构,网页结构),构思动手(选用什么HTML下载器,解析器等)。
在爬虫过程中,都会涉及到三种利器:
HTML下载器:下载HTML网页;
HTML解析器:解析出有效数据;
数据存储器:将有效数据通过文件或者数据库的形式存储起来。
1、将数据以字典形式建立
首先要知道,data里面的内容是都需要在代码中发送给服务器的。
2、反爬虫机制
理解反爬虫机制,找出加密参数。大多数网站的反爬虫的机制是对向服务器提交表单的动态值进行加密,所以,我们每翻译一次,就观察data里面有哪些参数是动态变化的。从这个网址来看,参数salt、sign对应的值是动态变化。找出动态参数的实现方式。根据反爬虫经验可知,一般网站生成的反爬加密值都是采用的时间戳,以及将一下字符串使用加密算法加密一下,我们可以从网页源代码中进行查找理解。
(1)、伪装浏览器:在 HTTP Request 中加入特定的 Header 要加入 header,需要使用 Request 对象。对有些 header 要特别留意,服务器会针对这些 header 做检查。
User-Agent : 有些服务器或 Proxy 会通过该值来判断是否是浏览器发出的请求
Content-Type : 在使用 REST 接口时,服务器会检查该值,用来确定 HTTP Body 中的内容该怎样解析。常见的取值有:
application/xml : 在 XML RPC,如 RESTful/SOAP 调用时使用
application/json : 在 JSON RPC 调用时使用
application/x-www-form-urlencoded : 浏览器提交 Web 表单时使用
在使用服务器提供的 RESTful 或 SOAP 服务时, Content-Type 设置错误会导致服务器拒绝服务。
(2)、调用代理访问
原因
:一个合格的网站为了防止服务器负载过大,也应该设置这样的机制来限制频繁请求。很多网站会检测某一段时间某个IP的访问次数,如果访问频率太快以至于看起来不像正常访客,它可能就会会禁止这个IP的访问。所以我们需要设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。
策略
:
采用时间间隔(单个IP):为了防止一个IP访问过于频繁而造成的的拒绝访问,治标的方法是,在求请访问的时候设置一定的时间间隔。import time ...... time.sleep(10) ......
采用动态代理(多个IP):可以事先获取cn-proxy代理的IP地址,写到一个列表内,采用随机的方法获取不同的代理ip地址。
requests、beautifulsoup
是爬虫两大神器,reuqests 用于网络请求,beautifusoup 用于操作 html 数据。
icrawler网址:
https://github.com/hellock/icrawler
二、Crawler安装
(base) C:\Users\Administrator>pip3 install icrawler
三、Crawler基本用法
内置爬虫
该框架包含6个内置的图像抓取工具。
- 谷歌
- bing
- 百度
- Flickr
- 通用网站图片爬虫(greedy)
UrlList(抓取给定URL列表的图像)
以下是使用内置抓取工具的示例。 搜索引擎抓取工具具有相似的界面。
from icrawler.builtin import BaiduImageCrawler
from icrawler.builtin import BingImageCrawler
from icrawler.builtin import GoogleImageCrawler
"""
parser_threads:解析器线程数目,最大为cpu数目
downloader_threads:下载线程数目,最大为cpu数目
storage:存储地址,使用字典格式。key为root_dir
keyword:浏览器搜索框输入的关键词
max_num:最大下载图片数目
"""
#谷歌图片爬虫
google_storage = {'root_dir': '/Users/suosuo/Desktop/icrawler学习/google'}
google_crawler = GoogleImageCrawler(parser_threads=4,
downloader_threads=4,
storage=google_storage)
google_crawler.crawl(keyword='beauty',
max_num=10)
#必应图片爬虫
bing_storage = {'root_dir': '/Users/suosuo/Desktop/icrawler学习/bing'}
bing_crawler = BingImageCrawler(parser_threads=2,
downloader_threads=4,
storage=bing_storage)
bing_crawler.crawl(keyword='beauty',
max_num=10)
#百度图片爬虫
baidu_storage = {'root_dir': '/Users/suosuo/Desktop/icrawler学习/baidu'}
baidu_crawler = BaiduImageCrawler(parser_threads=2,
downloader_threads=4,
storage=baidu_storage)
baidu_crawler.crawl(keyword='美女',
max_num=10)
GreedyImageCrawler
如果你想爬某一个网站,不属于以上的网站的图片,可以使用贪婪图片爬虫类,输入目标网址。
from icrawler.builtin import GreedyImageCrawler
storage= {'root_dir': '/Users/suosuo/Desktop/icrawler学习/greedy'}
greedy_crawler = GreedyImageCrawler(storage=storage)
greedy_crawler.crawl(domains='http://desk.zol.com.cn/bizhi/7176_88816_2.html',
max_num=6)
UrlListCrawler
如果你已经拥有了图片的下载地址,可以直接使用UrlListCrawler,为了高效抓取,可以使用多线程方式下载,快速抓取目标数据。
from icrawler.builtin import UrlListCrawler
storage={'root_dir': '/Users/suosuo/Desktop/icrawler学习/urllist'}
urllist_crawler = UrlListCrawler(downloader_threads=4,
storage=storage)
#输入url的txt文件。
urllist_crawler.crawl('url_list.txt')
定义自己的图片爬虫
通过icrawler我们很容易扩展,最简单的方式是重写Feeder,Parser和downloader这三个类。
Feeders:给crawler爬虫喂url,待爬
Parser:解析器(对某个url请求后得到该url的html文件,我们通过parser可以解析出html中的图片下载地址)
Downloader:图片下载器
Feeder
重写Feeder,需要改的方法:
feeder.feed(self, **kwargs)
如果你想一次提供一个起始url,例如从http://example.com/page url/1爬到http://example.com/page url/10 我们可以这样重写Feeder
from icrawler import Feederclass MyFeeder(Feeder):
def feed(self):
for i in range(10):
url = 'http://example.com/page_url/{}'.format(i + 1)
#感觉这里的output类似于yield一个url给downloader
self.output(url)
Parser
重写Parser,需要改的方法:
parser.parse(self, response, **kwargs)
对某个url请求后得到该url的html文件,我们通过parser可以解析出html中的图片下载地址。解析方法文档中建议使用BeautifulSoup,这里以GoogleParser为例
class GoogleParser(Parser):
def parse(self, response):
soup = BeautifulSoup(response.content, 'lxml')
image_divs = soup.find_all('div', class_='rg_di rg_el ivg-i')
for div in image_divs:
meta = json.loads(div.text)
if 'ou' in meta:
#将解析到的url以字典形式yield处理,注意字典的键使用的file_url
yield dict(file_url=meta['ou'])
Downloader
如果你想改变图片的保存时的文件名,可以这样重写方法
downloader.get_filename(self, task, default_ext)
默认的文件名命名规则是从000001 到 999999。这里是另外一种命名规则的实现
import base64from icrawler import ImageDownloader
from icrawler.builtin import GoogleImageCrawler
from six.moves.urllib.parse import urlparse
class PrefixNameDownloader(ImageDownloader):
def get_filename(self, task, default_ext):
filename = super(PrefixNameDownloader, self).get_filename(
task, default_ext)
return 'prefix_' + filename
class Base64NameDownloader(ImageDownloader):
def get_filename(self, task, default_ext):
url_path = urlparse(task['file_url'])[2]
if '.' in url_path:
extension = url_path.split('.')[-1]
if extension.lower() not in ['jpg', 'jpeg', 'png', 'bmp', 'tiff', 'gif', 'ppm', 'pgm']:
extension = default_ext
else:
extension = default_ext
# works for python 3
filename = base64.b64encode(url_path.encode()).decode()
return '{}.{}'.format(filename, extension)
google_crawler = GoogleImageCrawler(downloader_cls=PrefixNameDownloader,
# downloader_cls=Base64NameDownloader,
downloader_threads=4,
storage={'root_dir': 'images/google'})
google_crawler.crawl('tesla', max_num=10)
Crawler
到现在,我们可以使用自己重写的Feeder、Parser、Downloader,
storage={'backend': 'FileSystem', 'root_dir': 'images'}
crawler = Crawler(feeder_cls=MyFeeder,
parser_cls=MyParser,
downloader_cls=ImageDownloader,
downloader_threads=4,
storage=storage)
crawler.crawl(feeder_kwargs=dict(arg1='blabla', arg2=0),max_num=1000)