一、简单爬虫框架

  简单爬虫框架由四个部分组成:URL管理器、网页下载器、网页解析器、调度器,还有应用这一部分,应用主要是NLP配合相关业务。

  它的基本逻辑是这样的:给定一个要访问的URL,获取这个html及内容(也可以获取head和cookie等其它信息),获取html中的某一类链接,如a标签的href属性。从这些链接中继续访问相应的html页面,然后获取这些html的固定标签的内容,并把这些内容保存下来。

  一些前提:;所有要爬取的页面,它们的标签格式都是相同的,可以写一个网页解析器去获取相应的内容;给定的URL(要访问的资源)所获得的html,它包含的标签链接是可以筛选的,筛选后的标签链接(新的URL)会被继续请求其html文档。调度器是一个循环体,循环处理这些URL、请求以及html、网页解析。

  1.运行流程

      

    调度器是一个主循环体,负责不断重复执行URL管理器、下载器、解析器。URL是管理新的URL的添加、旧的URL的去除,以及URL的去重和记录。下载器顾名思义,就是根据URL,发送http请求,获取utf-8编码的字节流的html文件数据。解析器负责将html还原成DOM对象,并提供一套类似js的DOM操作的方法,从html中获取节点、属性、文本、甚至是样式等内容。

  2.URL管理器

    URL管理器有两个功能,获取待添加的URL--判断它是否在已被读取的URL集合里--[No]判断它是否在待读取的URL集合里--[No]添加到待读取的URL集合里。否则就直接抛弃。

    URL管理器一般放在内存、关系型数据库和缓存数据库里。python里可以使用set()集合去重。

  3.网页下载器

    向给定的URL发送请求,获取html。python的两个模块。内置urllib模块和第三方模块request。python3将urllib2封装成了urllib.request模块。

 # 网页下载器代码示例
import urllib url = "http://www.baidu.com" print("第一种方法: 直接访问url")
response1 = urllib.request.urlopen(url)
print(response1.getcode()) # 状态码
print(len(response1.read())) # read读取utf-8编码的字节流数据 print("第二种方法: 设置请求头,访问Url")
request = urllib.request.Request(url) # 请求地址
request.add_header("user-agent", "mozilla/5.0") # 修改请求头
response2 = urllib.request.urlopen(request)
print(response2.getcode())
print(len(response2.read())) import http.cookiejar # 不知道这是啥 print("第三种方法: 设置coockie,返回的cookie")
# 第三种方法的目的是为了获取浏览器的cookie内容
cj = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
urllib.request.install_opener(opener)
response3 = urllib.request.urlopen(url)
print(response3.getcode())
print(len(response3.read()))
print(cj) # 查看cookie的内容

  4.网页解析器

    将utf-8编码的字节码重新重新解析为html。因为数据传输是字节数据,所以网页下载器下载的内容需要重新解析。

    提供DOM对象[html文档解构]的操作方法。和js类似。包括节点、标签元素、属性[包括name、class、style、value等等]、样式、内容等的操作。从而能够获取特定的内容。

    python的BeautifulSoup模块(bs4)。以下代码可直接在bs4模块官方文档中获取和运行。

 from bs4 import BeautifulSoup
from re import compile
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p> <p class="story">...</p>
""" soup = BeautifulSoup(html_doc, "html.parser")
print(soup.prettify())
print(soup.title)
print(soup.title.name)
print(soup.title.string)
print(soup.title.parent.name)
print(soup.p)
print(soup.p['class'])
print(soup.a)
print(soup.find_all(href=compile(r"/example.com/\S*")))
print(soup.find_all('a'))
print(soup.find(id="link3"))
print(soup.get_text())
print(soup.find("p", attrs={"class": "story"}).get_text()) for link in soup.find_all('a'):
print(link.get('href'))

二、简单示例

  爬取百度百科上词条为python的以href='/tem/'开头的所有相关网页的词条简介。

 from re import compile
from html.parser import HTMLParser
from bs4 import # url管理器
class UrlManager(object):
"""
url管理器主要有三个功能:add_new_url添加新的待爬取的页面;get_new_url删除已爬取的页面;标记待爬取的和已爬取的页面。
"""
def __init__(self):
self.new_urls = set()
self.old_urls = set()
def add_new_url(self, url):
if url is None:
return
# 如果传入的url既不在待爬取的url里又不在爬过的url里,说明它是待爬取的url
if url not in self.new_urls and url not in self.old_urls:
self.new_urls.add(url) def add_new_urls(self, urls):
if urls is None or len(urls) == 0:
return
for url in urls:
self.add_new_url(url) def has_new_url(self):
return len(self.new_urls) != 0 def get_new_url(self):
new_url = self.new_urls.pop() # 从待爬去的url中剔除要爬取的目标
self.old_urls.add(new_url) # 添加到
return new_url # 简单的下载器
class HtmlDownloader(object):
def download(self, url):
if url is None:
return None
response = urllib.request.urlopen(url)
if response.getcode() != 200:
return None
return response.read() # 解析器
class HtmlParser(object):
def _get_new_urls(self, page_url, soup):
# 这里要提一下,百度百科python词汇的url是https://baike.baidu.com/item/Python/407313
# 页面中的a标签的href属性都类似href="/item/%E6%95%99%E5%AD%A6"这种属性
# 在处理时,需要加上baike.baidu.com保证url资源定位符的完整性。后面只需匹配"/item/"
new_urls = set()
links = soup.find_all('a', href=compile(r"/item/\S*"))
for link in links:
new_url = link["href"]
new_full_url = urllib.parse.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"></dd><h1>Python</h1>
title_node = soup.find("dd", attrs={"class": "lemmaWgt-lemmaTitle-title"}).find("h1")
res_data["title"] = title_node.get_text()
# 爬取简介内容
# <div class="lemma-summary" label-module="lemmaSummary"></div>
# 这个div下的所有div里的text
summary_node = soup.find('div', attrs={"class": "lemma-summary", "label-module":"lemmaSummary"})
res_data["summary"] = summary_node.get_text()
return res_data def parse(self, page_url, html_doc):
if page_url is None or html_doc is None:
return
# 解析成了一个整个的DOM对象,也就是纯html格式的文件
soup = BeautifulSoup(html_doc, "html.parser", from_encoding="utf-8")
new_urls = self._get_new_urls(page_url, soup)
new_data = self._get_new_data(page_url, soup)
# print("page_url: %r, new_urls: %r, new_data: %r" % (page_url, new_urls, new_data))
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("<meta http-equiv='content-type' content='text/html;charset=utf-8'>")
fout.write("<body>")
fout.write("<table>")
for data in self.datas:
fout.write("<tr>")
fout.write("<td>%s</td>" %data['url'])
fout.write("<td>%s</td>" %data['title'])
fout.write("<td>%s</td>" %data['summary'])
fout.write("</tr>")
fout.write("</table>")
fout.write("</body>")
fout.write("</html>") class SpiderMain(object):
def __init__(self):
self.urls = UrlManager()
self.downloader = HtmlDownloader()
self.parser = HtmlParser()
self.outputer = HtmlOutputer() def craw(self, root_url):
count = 1
self.urls.add_new_url(root_url)
while self.urls.has_new_url():
try:
new_url = self.urls.get_new_url()
html_cont = self.downloader.download(new_url)
# print("\033[1;36m %r \033[0m" % html_cont.decode("utf-8"))
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 == 11:break
print("\033[1;36m [CRAW]\033[0m : %d %r" %(count, new_url))
count += 1
except Exception as e:
print("craw failed")
print(e)
self.outputer.output_html()

    运行结果如下:

    打开保存的out.html,内容如下:

一、python简单爬取静态网页的更多相关文章

  1. 用python简单爬取一个网页

    1打开编辑器 2撸几行代码 import urllib.request import urllib.error def main(): askURl("http://movie.douban ...

  2. Python简单爬取Amazon图片-其他网站相应修改链接和正则

    简单爬取Amazon图片信息 这是一个简单的模板,如果需要爬取其他网站图片信息,更改URL和正则表达式即可 1 import requests 2 import re 3 import os 4 de ...

  3. python 简单爬取今日头条热点新闻(一)

    今日头条如今在自媒体领域算是比较强大的存在,今天就带大家利用python爬去今日头条的热点新闻,理论上是可以做到无限爬取的: 在浏览器中打开今日头条的链接,选中左侧的热点,在浏览器开发者模式netwo ...

  4. Python简单爬取图书信息及入库

    课堂上老师布置了一个作业,如下图所示: 就是简单写一个借书系统. 大概想了一下流程,登录-->验证登录信息-->登录成功跳转借书界面-->可查看自己的借阅书籍以及数量... 登录可以 ...

  5. Python开发爬虫之静态网页抓取篇:爬取“豆瓣电影 Top 250”电影数据

    所谓静态页面是指纯粹的HTML格式的页面,这样的页面在浏览器中展示的内容都在HTML源码中. 目标:爬取豆瓣电影TOP250的所有电影名称,网址为:https://movie.douban.com/t ...

  6. java爬虫-简单爬取网页图片

    刚刚接触到“爬虫”这个词的时候是在大一,那时候什么都不明白,但知道了百度.谷歌他们的搜索引擎就是个爬虫. 现在大二.再次燃起对爬虫的热爱,查阅资料,知道常用java.python语言编程,这次我选择了 ...

  7. Python:将爬取的网页数据写入Excel文件中

    Python:将爬取的网页数据写入Excel文件中 通过网络爬虫爬取信息后,我们一般是将内容存入txt文件或者数据库中,也可以写入Excel文件中,这里介绍关于使用Excel文件保存爬取到的网页数据的 ...

  8. python之爬取网页数据总结(一)

    今天尝试使用python,爬取网页数据.因为python是新安装好的,所以要正常运行爬取数据的代码需要提前安装插件.分别为requests    Beautifulsoup4   lxml  三个插件 ...

  9. python连续爬取多个网页的图片分别保存到不同的文件夹

      python连续爬取多个网页的图片分别保存到不同的文件夹 作者:vpoet mail:vpoet_sir@163.com #coding:utf-8 import urllib import ur ...

随机推荐

  1. Logstash 性能及其替代方案

    介绍 当谈及集中日志到 Elasticsearch 时,首先想到的日志传输(log shipper)就是 Logstash.开发者听说过它,但是不太清楚它具体是干什么事情的: 当深入这个话题时,我们才 ...

  2. linux 查看进程所在目录

    一下内容转自:https://blog.csdn.net/spring21st/article/details/50561550 通过 ps 及 top 命令查看进程信息时,只能查到 相对路径,查不到 ...

  3. [AIR] AIR将数据保存并导出为Excel

    package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.filesystem.File; ...

  4. mysql 代价

    mysql cbo cost base optimizer 基于代价,数据是一直变化的oracle8 以前是rbo rule base optimizer 基于规则, 如果sql使用了索引,必须使用索 ...

  5. 如何解决 “invalid resource directory name”, resource “crunch”

    Ant and the ADT Plugin for Eclipse are packing the .apk file in a different build chain and temp gen ...

  6. jquery选项卡效果

    效果图: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  7. 比较 GET 与 POST

    post比get安全 get请求方法向url添加数据  全部用POST不是十分合理,最好先把请求按功能和场景分下类, 对数据请求频繁,数据不敏感且数据量在普通浏览器最小限定的2k范围内,这样的情况使用 ...

  8. [蓝桥杯][2016年第七届真题]路径之谜(dfs)

    题目描述 小明冒充X星球的骑士,进入了一个奇怪的城堡. 城堡里边什么都没有,只有方形石头铺成的地面. 假设城堡地面是 n x n 个方格.[如图1.png]所示. 按习俗,骑士要从西北角走到东南角. ...

  9. dp--hdu1171(01背包)

    hdu1171 题目 Problem Description Nowadays, we all know that Computer College is the biggest department ...

  10. 原子操作类AtomicInteger详解

    为什么需要AtomicInteger原子操作类?对于Java中的运算操作,例如自增或自减,若没有进行额外的同步操作,在多线程环境下就是线程不安全的.num++解析为num=num+1,明显,这个操作不 ...