《python网络数据采集》读书笔记

本书详述网络数据采集的原理与实践,包括创建爬虫、解析HTML、使用API、存储数据、处理复杂HTML、JavaScript采集、图像识别、应对反爬策略等内容,通过实例介绍BeautifulSoup、Selenium、Scrapy等工具的使用。强调道德规范,提醒注意速度和避免IP封锁。
摘要由CSDN通过智能技术生成

《python网络数据采集》读书笔记

标签(空格分隔): python 爬虫 读书笔记


花了三天时间看了一遍,将我认为值得记下的内容记录了下来。推荐购买。

第一部分 创建爬虫

重点介绍网络数据采集的基本原理。
* 通过网站域名获取HTML数据
* 根据目标信息解析数据
* 存储目标信息
* 如果有必要,移动到另一个网页重复这一过程

第1章 初见网络爬虫

from urllib.request import urlopen,查找python的request模块,只导入一个urlopen(python3)
urllib是python的标准库,包含了从网络请求数据,处理cookie,甚至改变请求头和用户代理这些元数据的函数。
python文档
而urlopen用来打开并读取一个从网络获取的远程对象。

1.2 Beautiful Soup简介

BeautifulSoup可以通过定位HTML标签来格式化和组织复杂的网络信息。

用虚拟环境保存库文件

如果同时负责多个python项目,或者想要轻松打包某个项目及其关联的库文件,或者担心已经安装的库之间可能有冲突,可以安装一个python虚拟环境来分而治之。
使用virtualenv scrapingEnv就可以创建一个虚拟环境
激活并使用

cd scrapingEnv/
source bin/activate

激活后,就会发现环境名称出现在命令行提示符之前,后面你安装的任何库和执行的任何程序都是在这个环境下运行。
当不再使用虚拟环境中的库时,可以通过释放命令退出环境deactivate

1.2.2 运行BeautifulSoup

BeautifulSoup中最常用的就是BeautifulSoup对象
任何HTML文件的任意节点信息都可以被提取出来,只要目标信息的旁边或附近有标记就行。

1.2.3 可靠的网络连接

网络连接代码可能会出现异常,需要进行处理。
html=urlopen("http://www.pythonscraping.com/pages/page1.html")
这行代码主要可能会发生两种异常:
* 网页在服务器上不存在,或者获取页面的时候出现错误
* 服务器不存在
第一种会返回HTTP错误,可能是404 Page Not Fund,或是500 Internal Server Error,这时urlopen函数会抛出HTTPError异常,可以这样处理

try:
    html=urlopen("http://www.pythonscraping.com/pages/page1.html")
except HTTPError as e:
    print (e)
    #返回空值,中断程序,或者执行另一种方案
else:
    #程序继续。如果你已经在上面异常捕捉那一段代码立返回或中断,那么就不需要else语句了,这段代码也不会执行

如果服务器不存在,urlopen会返回一个None对戏那个,可以使用html is None来判断这个返回的html是不是None
即使成功从服务器获取网页,如果网页上的内容并非完全是我们期望的那样,仍然可能会出现异常。因此每当你调用BeautifulSoup对象里的一个标签时,增加一个检查条件保证标签确实存在是一个很聪明的做法。如果标签不存在,BeautifulSoup会返回None对象。如果再调用这个None对象下的子标签,就会发生AttributeError错误。

第2章 复杂HTML解析

2.1 不是一直都要用锤子

假如已经确定了目标内容,如果使用复杂的嵌套查询来获取的话,不仅欠缺美感,而且如果网站管理员对网站稍作修改后,代码就会失效。
* 寻找“打印此页”的链接,或者看看有没有HTML样式更加友好的移动版
* 寻找隐藏在JavaScript文件里的信息。
* 可以尝试从URL链接里获取
* 从其他网站上查询

2.2 再端一碗BeautifulSoup

介绍通过属性查找标签的方法,标签组的使用,以及标签解析树的导航过程。
使用findAll函数来抽取只包含在<span class = "green"></span>标签里的文字
.get_text()会把你正在处理的HTML文档中所有的标签都清除,然后返回一个只包含文字的字符串。通常在准备打印、存储和操作数据时,应该最后才使用.get_text()

2.2.1 BeautifulSoup的find()和findAll()

借助它们,你可以通过标签的不同属性轻松地过滤HTML页面,查找需要的标签组或单个标签
findAll(tag,attributes,recursive,text,limit,keywords)
find(tag,attributes,recursive,text,keywords)
标签参数tag:一个标签的名称或是多个标签名称组成的python列表
属性参数attributes是用一个python字典封装一个标签的若干属性和对应的属性值。
递归参数recursive是一个布尔变量。如果设置为true,findAll会根据你的要求去查找标签参数的所有子标签,以及子标签的子标签。如果设置为false,则只查找文档的一级标签
文本参数text使用标签的文本内容去匹配。比如要查找包含”the prince”内容的标签数量,可以:

nameList = bsObj.findAll(text = "the prince")
print(len(nameList))

输出结果为7。
范围限制参数limit,只用于findAll方法(find方法等价于findAll的limit等于1时的情形)。如果你只对网页中获得的前x项结果感兴趣,就可以设置它。顺序按照网页上的顺序排序。
关键词参数keyword,可以选择具有指定属性的标签:

allText = bsObj.findAll(id="text")
print(allText[0].get_text())

标签参数tag把标签列表传到.findAll()里获取一列标签,实际上是或关系的过滤器。而关键词参数keyword可以让你增加一个与关系的过滤器来简化工作。

2.2 其他BeautifulSoup对象

目前已经介绍了两种对象:
* BeautifulSoup对象
* 标签Tag对象
还有另外两种对象:
* NavigableString对象:用来表示标签里的文字,而不是标签
* Comment对象:用来查找HTML文档的注释标签

2.3 导航树

findAll函数通过标签的名称和属性来查找标签,而导航树则是通过标签在文档中的位置来查找标签。如单一方向的导航bsObj.tag.subTag.anotherSubTag
对标签Tag对象使用children()函数可以获得所有子标签。
使用descendants()函数可以打印所有后代标签。

处理兄弟标签
使用next_siblings()函数可以便捷地处理带标题行的表格。

让标签的选择更加的具体:页面的布局总是不断变化,如果想让爬虫更稳定,最好还是让标签的选择更加具体。如果有属性,就利用标签的属性。
和next_siblings()一样,如果你很容易找到一组兄弟标签中的最后一个标签,那么previous_siblings函数也会很有用。
还有next_sibling和previous_sibling函数,只不过返回的是单个标签。

父标签处理:
使用parent和parents可以查找父标签

2.3 正则表达式

正则表达式是可以识别正则字符串(regular string)的式子。也就是说,它们可以这么定义:“如果你给我的字符串符合规则,我就返回它”,或者是“如果字符串不符合规则,我就忽略它”
可以去RegexPal这类网站上在线测试正则表达式。
正则表达式的一个经典的应用是识别邮箱地址。比如[A-Za-z0-9\._+]+@[A-Za-z]+\.(com|org|edu|net)
正则表达式常用的符号

符号 含义
* 匹配,0次或多次
+ 匹配,至少1次
[] 匹配任意一个字符(相当于任选一个)
() 表达式编组(会优先执行)
{m,n} 匹配,从m到n次
[^] 匹配任意一个不再中括号内的字符
| 匹配任意一个由竖线分割的字符、子表达式
. 匹配任意单个字符
^ 指字符串开始位置的字符或子表达式
| 转义字符
$ 常用在末尾,表示“从字符串的末端匹配”。不然,每个正则表达式默认为”.*”,只会从开头匹配
?! 不包含。通常放在字符或正则表达式前面,表示字符不能出现在目标字符串里。如果要在整个字符串全部排除某个字符,就要加上^和$
2.4 正则表达式和BeautifulSoup

大多数支持字符串参数的函数都可以用正则表达式实现。
例子:从网页中获取商品图片,如果直接获取img标签,可能会有其他图片。但是考虑到商品的图片大多放在同一个文件夹中,如果用下面的程序可以快速获得。

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html)
images = bsObj.findAll("img",{
  "src":re.compile("\.\./img\/gifts/img.*\.jpg")})#显然,图片的相对路径都是以../img/gifts/img开头,以.jpg结尾。

正则表达式可以作为BeautifulSoup语句的任意一个参数,让目标元素查找工作极具灵活性。

2.5 获取属性

有些需要的信息藏在标签属性中,比如\的URL链接,\的图片文件
对于一个标签属性,可以用下面的代码获取它的全部属性
myTag.attrs
它返回的是一个python字典对象,要获取src可以这样获取
myImgTag.attrs["src"]

2.6 Lambda表达式

BeautifulSoup允许把特定函数类型当作findAll函数的参数,唯一的限制条件就是这些函数必须把一个标签作为参数,并且返回结果为布尔类型。BeautifulSoup用这个函数来评估它遇到的每个标签对象,最后把评估结果为真的标签保留,把其他标签剔除。
例如,下面的代码就是获取有两个属性的标签:
soup.findAll(lambda tag: len(tag.attrs)==2)

2.7 超越Beautiful Soup

BeautifulSoup是python里最受欢迎的HTML解析库之一,但它并不是唯一的选择。
* lxml
* HTML parser

第3章 开始采集

3.2 采集整个网站

深网和暗网
深网指的是搜索引擎无法抓取到的那部分网络。
暗网是基于TOR客户端的。

显然,需要使用一个方便查询的列表(例子中使用了set类型)来去重

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

pages = set()
def getLinks(pageUrl):
    global pages
    html = urlopen("http://en.wikipedia.org"+pageUrl)
    bsObj = BeautifulSoup(html)
    for link in bsObj.findAll("a",href = re.compile("^(/wiki/)")):
        if 'href' in link.attrs:
            if link.attrs['href'] not in pages:
                #如果遇到了新的页面
                newPage = link.attrs['href']
                print(newPage)
                pages.add(newPage)
                getLinks(newPage)
getLinks("")
递归的警告

python默认的递归调用限制为1000次。

3.4 用Scrapy采集

Scrapy可以帮你大幅度降低网页链接查找和识别工作复杂度的python库。
创建Scrapy项目:scrapy startproject wikiSpider,这样就创建了名为wikiSpider的新项目。当前目录出现了名为wikiSpider的项目文件夹。
为了创建爬虫,需要在wikiSpider/wikiSpider/spiders文件夹里增加一个articleSpider.py文件。另外,在items.py文件中,需要定义一个Article类。
items.py文件:

#...
from scrapy import Item,Field

class Article(Item):
    title = Field()

Scrapy的每个Item(条目)对象表示网站上的一个页面。下面演示收集每页的title字段

articleSpider.py:

from scrapy.selector import Selector
from scrapy import Spider
from wikiSpider.items import Article

class ArticleSpider(Spider):
    name = "article"
    allowed_domains = ["en.wikipedia.org"]
    start_urls = ["http://en.wikipedia.org/wiki/Main_Page","http://en.wikipedia.org/wiki/Python_%28programming_language%29"]

    def parse(self, response):
        item = Article()
        title = response.xpath('//h1/text()')[0].extract()
        print("Title is: "+ title)
        item['title'] = title
        return item

然后在wikiSpider主目录中使用scrapy crawl article来运行ArticleSpider(由条目名称article来调用爬虫,是ArticleSpider的name=”article”决定的)

Scrapy日志处理

可以在Scrapy的setting.py中设置日志显示层级:LOG_LEVEL = 'ERROR'
也可以通过下面的命令输出到一个独立的文件中:scrapy crawl article -s LOG_FILE = wiki.log

Scrapy用Item对象决定要从它浏览的页面中提取哪些信息。支持不同的输出格式。
Scrapy文档

第4章 使用API

API调用

不同API的调用语法大不相同,但是有几条共同准则。当使用GET请求获取数据时,用URL路径描述你要获取的数据范围,查询参数可以作为过滤器或附加请求使用。

Twitter、Google的API

4.7 解析JSON数据

使用Python标准库中的JSON解析库来进行解析。使用import json来使用它。

4.9 再说一点API

优质资源:
Leonard Richardson、Mike Amundsen和Sam Ruby的RESTful Web APIs,为网络API的用法提供了非常全面的理论与实践直到
创建自己的API:Mike Amundsen的精彩视频教学课程Designing APIs for the Web(http://shop.oreilly.com/product/119999125.do)

第5章 存储数据

主要介绍三种数据管理方法:数据库、文件和邮件

5.1 媒体文件

存储媒体文件的两种主要方式:只获取文件URL链接,或者直接把源文件下载下来。
在Python 3.x版本中,urllib.request.urlretrieve可以根据文件的URL下载文件:

from urllib.request import urlretrieve
from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("http://www.pythonscraping.com")
bsObj = BeautifulSoup(html)
imageLocation = bsObj.find("a",{
  "id":"logo"}).find("img")["src"]
urlretrieve(imageLocation,"logo.jpg")

上面这个例子从http://pythonscraping.com下载logo图片,然后在程序运行的文件夹里保存为logo.jpg文件。

程序运行注意事项

当你运用管理员程序运行下载程序的时候,你的电脑基本已经处于危险之中。所以应该时刻注意。

5.2 把数据存储到csv

CSV(逗号分隔值)是存储表格数据的常用文件格式。
CSV的每一行都用一个换行符分隔,列与列之间用逗号分隔。还可以用Tab字符或其他字符分隔行,不过用的不多。
如果只需要下载csv文件,使用上面介绍的方法已经足够。下面介绍的是如何下载并修改csv文件,甚至从零创建一个csv文件。
使用python的csv库。

import csv

csvFile = open("../files/test.csv",'w+')
try:
    writer = csv.writer(csvFile)
    writer.writerow(('number','number plus 2','number times 2'))
    for i in range(10):
        writer.writerow((i,i+2,i*2))
finally:
    csvFile.close()

网络数据采集的一个常用功能就是获取HTML表格并写入CSV文件。比如下面就是将维基百科复杂的HTML表格变为CSV文件的例程:

import csv
from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("http://en.wikipedia.org/wiki/Comparison_of_text_editors")
bsObj = BeautifulSoup(html)
#主对比表格是当前页面上的第一个表格
table = bsObj.findAll("table",{
  "class":wikitable})[0]
rows = table.findAll("tr")

csvFile = open("../files/editors.csv",'wt',newline="",encoding='utf-8')
writer = csv.writer(csvFile)
try:
    for row in rows:
    csvRow = []
    for cell in row.findAll(['td','th'])
        csvRow.append(cell.get_text())
        writer.writerow(csvRow)
finally:
    csvFile.close()
5.3 MySQL

使用MySQL前要进行预先安装,然后启动服务器,使用python代码与服务器进行交互

5.3.3 与Python整合

python没有内置的MySQL支持工具,不过有很多开源的库,最著名的是PyMySQL
可以使用下面的命令来安装它

curl -L https://github.com/PyMySQL/PyMYSQL/tarball/pymysql-0.6.2 | tar xz
cd PyMySQL-PyMyQL-f953785/
python setup.py install

需要检查最新版并更新第一行的URL
安装完后就可以执行下面的语句

import pymysql
conn = pymysql.connect(host='127.0.0.1',unix_socket = '/tmp/mysql.sock',user = 'root',passwd = None,db='my
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值