黄金城手机网站
  咨询电话:15208869596

hjc澳门黄金城

爬虫——综合案例流程版

爬虫综合案例

开发步骤:

导入类库创建爬虫通用类初始化init方法类中编写重试下载模块类中编写真正下载模块类外编写保存函数类外编写获取robots.txt函数类外编写抽取网址函数类中编写网址正常化函数创建下载限流类爬虫通用类封装run方法创建爬虫对象运行

导入类库

requests:爬虫请求类库hashlib:哈希加密类库queue:队列re:正则time:时间threading>Thread:多线程datetime>datetime:日期时间urllib>parse>urlparse,urljoin,urldefrag:网址解析、拼接、截#取urllib>robotparser:robot.txt解析目录名>文件名>MongoCache:存储到mongodb

创建爬虫通用类

功能:从初始网址爬取并抽取内层网址继续爬取技术:随机User-Agent生成,队列,多线程,robots解析,下载限流,mongodb存储,爬取深度限制,重试下载,抽取特定路由,真正下载,网址正常化,功能封装规范:用到类属性和类方法的方法在类里编写,用不到的在类外面编写,可以建个助手目录utils存放这些助手函数

初始化init方法

通常在开发过程中不可能一下子就把init写得完整,先把最易用到的,已经想到的初始化,后面的在编写其他函数想到时再来init里编写

生成UserAgent对象,随机生成headers保存初始网址创建队列并放入初始网址

使用不同的队列会造成BFS和DFS的效果 使用先进先出队列产生广度优先搜索,使用先进后出(栈)产生深度优先搜索

创建robots解析对象传入初始网址设置指定路由创建限流器对象并初始化间隔时间创建mongodb存储对象设置网址访问深度,在类外设置最大深度定量

类中编写重试下载模块

调用retry装饰器装饰该函数并设置最多重试次数设置函数参数:网址,数据,请求方式,代理编写POST和GET爬取方式插入断言:状态码不为200则抛出异常返回爬取结果content

text:返回的是unicode 型的数据,一般是在网页的header中定义的编码形式,如果想要提取文本就用text;content:返回的是bytes,二级制型的数据;想要提取图片、文件,就要用到content;.text是现成的字符串,.content还要编码,但是.text不是所有时候显示都正常,这是就需要用.content进行手动编码。

类中编写真正下载模块

将重试下载模块封装在此,不对用户展示重试下载接口

 

函数参数:网址,数据(默认None),请求方式(默认GET),代理(默认为空)输出一句下载信息try~except 捕获重试下载模块的异常返回结果

类外编写保存函数

保存函数:将爬取内容MD5加密存储到文件中,注:使用mongodb保存结果则无需次函数

 

创建md5加密对象加密update结果拼接保存文件路径写入文件

类外编写获取robots.txt函数

创建robot文件解析对象拼接robots.txt所在完整地址获取robots.txt文件将robot.txt文件读取到rp对象中返回该解析对象

类外编写抽取网址函数

方式:lxml、BeautifulSoup、正则

lxml

1 html = lxml.html.fromstring(html_content)2 html_data = html.xpath("//a/@href")

BeautifulSoup

1 soup = BeautifulSoup("lxml")2 a_list = soup.find_all("a")3 for a in a_list:4 print(a["href"])

正则

1 url_regex = re.compile("<a[^>]+href=[""](.*?)[""]", re.IGNORECASE)2 return url_regex.findall(html_content.decode("utf-8"))

decode解码问题:不同网站所使用的编码方式有所不同—— utf-8 , gbk, gb2312, ISO-8859-1

类中编写网址正常化函数

实现一个类方法的时候,要注意类方法是否使用了当前类的属性或其他方法,如果未使用就说明和当前类没有直接关系,最好独立出来,当做工具方法

 

以网址中的#进行分割(urldefrag),提取出网址部分和#后的转发部分将下载地址拼接上网址部分(urljoin)

1 urljoin:拼接网址,若参数2网址是正确格式,那么拼接的结果只是参数2网址,参数1网址忽略;若参数2网址是错误格式或是后缀path,那么和参数1网址进行拼接 2 urljoin("http://www.baidu.com","/ljb.html/index.html") 3 "http://www.baidu.com/ljb.html/index.html" 4 5 urljoin("http://www.baidu.com","http://ljb.html/index.html") 6 "http://ljb.html/index.html" 7 8 urljoin("/www.baidu.com","http://ljb.html/index.html") 9 "http://ljb.html/index.html"10 11 urljoin("/test.html","http://ljb.html/index.html")12 "http://ljb.html/index.html"13 14 urljoin("http://www.baidu.com/test.html","http://ljb.html/index.html")15 "http://ljb.html/index.html"16 17 urljoin("http://www.baidu.com/test.html","http://www.sina.com/ljb.html/index.html")18 "http://www.sina.com/ljb.html/index.html"

创建下载限流类

限流:设置爬取的间隔时间是为了避免IP被封锁,随机间隔时间更可靠

初始化方法

创建domains字典,网址为键,访问时间为值传参delay,自行设置两次下载间隔时间

间隔方法

原理:以delay作为时间间隔或超过delay才可进行访问(爬取)第一次访问:获取不到网址对应的访问时间(不执行if-else语句),以网址地址为键,访问时间为值存入字典第二次访问:获取上次访问对应网址的访问时间,进行if-else判断,计算时间差注:若delay>(这次访问时间-上次访问时间),说明还没等够,还需要继续等待,还需等待的时间是——总等待时间delay减去已经等待的时间(就是当前时间减去本次访问的时间)注:若delay<(这次访问时间-上次访问时间),说明已经等够了,可以直接访问得到键(域名):urlparse().netloc

1 urlparse("http://www.baidu.com/index.html?x=123&y=789#13579")2 ParseResult(scheme="http", netloc="www.baidu.com", path="/index.html", params="", query="x=123&y=789", fragment="13579")从domains字典中get获取上次访问时间通过ifelse计算还需等待的时间并睡眠(time.sleep) -一次访问后保存本次访问到domains字典中

爬虫通用类封装run方法

执行流程

判断队列中是否存在待爬取的网址判断爬取网址是否遵守robots约定,不遵守则跳出禁止下载对当前爬取网址限流获取当前的访问深度判断当前访问深度是否在规定范围内下载爬取网址得到爬取结果判断爬取结果是否为空爬取结果不为空则保存获取出爬取结果里的所有链接使用过滤器筛选出指点关键字的链接for循环补全每个链接补全同时判断链接是否访问过未被访问过则深度加1并加入队列, 1, 0, 9);