- 基本的爬虫工作原理
 - 基本的http抓取原理,scrapy
 - Bloom Filter:
 - 分布式爬虫概念
 - rq和Scrapy的结合
 - 后续处理,网页析取
 
假如是一只蜘蛛,爬到第一个页面,然后把页面全部抄下来,用脑子存下所看过的页面地址,每次想爬一个新链接都要去查一下这个页面是否去过,去过就不去了。(地址判重)
流程
发送请求–获得页面–解析页面–下载内容–存储内容。
准备内容:
list,dict:用来序列化你爬的东西
切片:用来对爬取的内容进行分割,生成
条件判断(if等):用来解决爬虫过程中哪些要哪些不要的问题
循环和迭代(for while ):用来循环,重复爬虫动作
文件读写操作:用来读取参数、保存爬下来的内容等
url管理器:管理将要爬取的url和已经爬取的url,防止重复抓取和循环抓取。
网页下载器
网页解析器
具体流程
将url管理器中待爬取的url送给网页下载器,网页下载器将其存储下来存为一个字符串,传送给网页解析器进行解析,每个网页都有指向其他网页的url也可以将其解析之后送给url管理器。
形成循环
爬虫架构动态工作流程
- 调度器去问url管理器有没有待爬取的url,返回是或否给调度器,如果是的话,调度器从url管理器中取出一个待爬取的url,url管理器将这个url返回给调度器。
 - 现在调度器得到了这个url,调度器将url传送给下载器下载内容,下载好之后将url内容返回给调度器。
 - 调度器将url的内容传送给解析器进行网页解析。解析之后返回有价值的数据和新的url列表。
 - 一方面调度器将价值数据传送给应用进行数据收集,另一方面将新的url列表补充到url管理器。
 - 如果url管理器还有新的待爬url,就将其循环。
 - 等到url管理器没有待爬的url,将其价值数据发到应用上。
 
网页下载器urllib下载的三种方法: 
 1. python 3.x中urllib库和urilib2库合并成了urllib库。 
 其中urllib2.urlopen()变成了urllib.request.urlopen() 
 urllib2.Request()变成了urllib.request.Request() 
import urllib #加载urllib模块
response = urllib.request.urlopen("http://www.baidu.com")#直接请求
print(response.getcode())#获取网页的返回码
cont  = response.read()#读取内容
print(cont)  - 添加data,http header 
向服务器提交需要用户输入的数据,将url,data,http header三个参数传送给urllib.request.Request()类,生成一个request对象,然后依然用urllib.request.urlopen打开
,以request作为参数。 
import urllib.request
url = 'https://www.zhihu.com/'
req = urllib.request.Request(url)
req.add_data('a','1')#添加数据
req.add_header('User-Agent','Mozilla')#伪装成浏览器
f = urllib.request.urlopen(req)
print(f.read().decode('utf-8'))
  3添加特殊情景的处理器
有些网页需要用户登录才能访问,有些网页需要代理才能访问,还有一些网页是用https加密的,
++Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。++
import http.cookiejar, urllib
cj = http.cookiejar.CookieJar()#创建cookie容器
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))#创建一个opener
urllib.request.install_opener(opener)#给urllib安装opener
url = 'https://www.zhihu.com/'
response = urllib.request.urlopen(url)
print(response.read())
  网页解析器:从网页中提取有价值数据的工具
结构化解析,通过一个树来进行遍历。
创建beautifulsoup对象,搜索节点find_all,find,访问节点,名称,属性,文字。
find_all(name,attrs,string)#节点的名称,节点的属性,节点的文本
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'html.parser')
links = soup.find_all('a')
for link in links:
    print(link.name,link['href'],link.get_text())  link_node = soup.find('a',href='http://example.com/lacie')
print(link_node.name,link_node['href'],link_node.get_text())  正则匹配
p_node = soup.find('p',class_="title")
print(p_node.name,p_node.get_text())  实例爬虫
- 确定目标
 
抓取百度百科python词条以及相关词条页面的标题和简介
- 分析目标 
- 抓取目标页面的url格式,限定抓取页面的范围
 - 分析抓取数据的格式,本实例就是抓取标题和简介
 - 分析页面的编码
 
 - 编写代码
 - 执行代码
 
入口页
http://baike.baidu.com/item/Python
新建一个python package
# main
from baike_spider import html_downloader
from baike_spider import html_outputer
from baike_spider import html_parser
from baike_spider import url_manager
class SpiderMain(object):
    def __init__(self):
        self.urls = url_manager.UrlManager()
        self.downloader = html_downloader.HtmlDownloader()
        self.parser = html_parser.HtmlParser()
        self.outputer = html_outputer.HtmlOutputer()
    def craw(self, root_url):
        count = 1
        self.urls.add_new_url(root_url)
        while self.urls.has_new_url():#待爬取url不为空
            try:
                new_url = self.urls.get_new_url()#取出待爬取URL集合中的一个url
                print('craw %d : %s'%(count, new_url))
                html_cont = self.downloader.download(new_url)#将这个url指向的网页下载下来
                new_urls, new_data  =  self.parser.parse(new_url, html_cont)
                self.urls.add_new_urls(new_urls)
                self.outputer.collect_data(new_data)
                if(count == 1000):
                    break
                count = count+1
            except:
                print('craw failed')
        self.outputer.output_html()
if __name__=="__main__":
    root_url = "http://baike.baidu.com/item/%E4%BA%92%E8%81%94%E7%BD%91/199186"
    obj_spider = SpiderMain()
    obj_spider.craw(root_url)  其余的是module
#url管理器
class UrlManager(object):
    def __init__(self):
        self.new_urls = set()#待爬取的url集合
        self.old_urls = set()#已爬取的url集合
    def add_new_url(self, url):#添加新的url
        if url is None:
            return
        if url not in self.new_urls and url not in self.old_urls:#如果这个url不在待爬取的url中也不在已爬取的url中
                self.new_urls.add(url)#那么就将其添加到待爬取的url集合中
    def add_new_urls(self, urls):#添加url集合
        if urls is None or len(urls) == 0:
            return
        for url in urls:
            self.add_new_url(url)#进行单个的添加
    def has_new_url(self):#判断待爬取的url集合是否为空
        return len(self.new_urls) != 0#不为空的话return1 为空的话return0
    def get_new_url(self):#取出待爬取集合中的url
        new_url = self.new_urls.pop()
        self.old_urls.add(new_url)#将这个url添加到已爬取的url集合中
        return new_url  #网页下载器
import urllib.request
class HtmlDownloader(object):
    def download(self, url):
        if url is None:
            return None
        response = urllib.request.urlopen(url)#将url下载
        if response.getcode() != 200:#网页访问失败
            return None
        return response.read()#返回网页的字符串  #网页解析器
from bs4 import BeautifulSoup
import re
from urllib.parse import urljoin
class HtmlParser(object):
    def _get_new_urls(self, page_url, soup):
        new_urls = set()
        links = soup.find_all('a',href = re.compile(r"/view/\d+\.htm"))
        for link in links:
            new_url = link['href']
            new_full_url = urljoin(page_url,new_url)
            new_urls.add(new_full_url)
        return new_urls
    def _get_new_data(self, page_url, soup):
        res_data = {}
        res_data['url'] = page_url
        #<dd class="lemmaWgt-lemmaTitle-title">
        #<h1>Python</h1>
        title_node = soup.find('dd',class_="lemmaWgt-lemmaTitle-title").find("h1")
        res_data['title'] = title_node.get_text()
        #<div class="lemma-summary" label-module="lemmaSummary">
        summary_node = soup.find('div',class_ = "lemma-summary")
        res_data['summary'] = summary_node.get_text()
        return res_data
    def parse(self, page_url, html_cont):
       if page_url is None or html_cont is None:
           return
       soup = BeautifulSoup(html_cont,'html.parser')
       new_urls = self._get_new_urls(page_url,soup)
       new_data = self._get_new_data(page_url,soup)
       return new_urls, new_data  #输出
class HtmlOutputer(object):
    def __init__(self):
        self.datas = []
    def collect_data(self, data):
        if data is None:
            return
        self.datas.append(data)
    def output_html(self):
        fout = open('output.html','w',encoding ='utf-8')
        fout.write("<html>")
        fout.write("<body>")
        fout.write("<table>")
        for data in self.datas:
            fout.write("<tr>")
            fout.write("<td>%s</td>" % data['url']+'\n')
            fout.write("<td>%s</td>" % data['title']+'\n')
            fout.write("<td>%s</td>" % data['summary']+'\n')
        fout.write("/<table>")
        fout.write("/<body>")
        fout.write("/<html>")
京公网安备 11010502036488号