爬虫知识结构

爬虫体系归纳。

1. 爬虫基础

爬虫工程师的前景、爬虫工作原理、网络爬虫工作原理详解

  • 从结构化(HTML)和非结构化(流数据)的数据中获取信息
    什么是网络爬虫、如何分析静态网站、如何开发一个完整的爬虫
    动态网站分析和爬取的两种思路
    如何从HTML页面中提取出有效的数据,以及对如何将数据合理地存储成各类文件以实现持久化。
    一个爬虫所应该具有的全部功能组件以及编码实现
    分布式爬虫,功能和基础爬虫一致,在单机爬虫的基础上进行分布式改进,帮助大家从根本上了解分布式爬虫,消除分布式爬虫的神秘感。
    、动态网站的抓取、协议分析
    爬虫的设计及实现流程
    熟悉抓包分析请求并模拟
    正则表达式、Path、css选择器、Xpath
    熟练使用selenium、lxml、bs4,对xml、html的文本进行抓取解析清洗
    完整地介绍了爬虫程序的每一个知识模块
    网络爬虫
    组成
    什么是
    初识
    爬虫(网页)抓取原理及技术
    基本议题和框架
    遇到爬虫问题的时候的各种解决方法

    1.1. 为什么要学

    为什么、好处、重要性、作用、意义、优势、不足、历史、现状、趋势、大背景。
    不断解决遇到的疑惑。
    科技如何给大家带来实效
    数据的存储对公司有什么影响
    如何存储数据⇒高效利用 方便对接其他部门和业务
    如何使用淘宝网上所有绿色产品(如空气净化器)的销量数据来做潜在市场评估
    如何一直高效率、持续不断地从日新月异的网站中获取信息
    互联网的运作和结构
    爬虫程序是收集信息的基础。
  • 学习网络爬虫的原因
  • 网络爬虫带来的价值
  • 飞速发展的大数据时代。
    市场营销:丰富的数据信息让我们有能力更好地了解消费者、顾客和竞争对手。电商网站评论收集可以及时知悉顾客对于产品的看法,通过微博数据收集可以及时洞察潜在消费者的购买意向和需求。
    企业管理人员:通过对手网站信息收集可以及时知晓对手的实时动态,真正做到运筹帷幄之中,决胜千里之外。
    打开数据信息收集大门的钥匙。
    有志于在数据分析方面有所突破。
    使用Python编写网络爬虫程序获取互联网上的大数据是当前的热门专题。
    技术创新驱动变革的潮流。
    数据量爆发式增长的互联网时代。
    大数据分析的火热。
    大数据成为业界与学术界最火热的话题之一。
    数据已经成为每个公司极为重要的资产。
    互联网大量的公开数据为个人和公司提供了以往想象不到的可以获取的数据量。
    网络爬虫技术是大数据分析的第一环。有助于获取有用的公开数据集。
    理解了信息的获取、存储和整理,才有可能系统地收集和应用不同源头和千变万化的网站信息。
    DT的核心是从信息的源头去理解和分析,以做出能打动对方的行动决策方案。
    由谷歌搜索到现在的大数据时代,爬虫技术的重要性和广泛性一直很突出。
    爬取目标网站的资料、分析和建立应用。 获取数据自动、实时、及时、省时。
    电商市场的重要性日益凸显。了解对手的产品特点、价格以及销量情况,及时跟进产品开发进度和营销策略,从而知己知彼,赢得竞争。过去,两个痛点——无法自动化和无法实时获取。产品研发部门会手动访问一个个电商产品页面,人工复制并粘贴到Excel表格中,制作竞品分析报告。但是这种重复性的手动工作不仅浪费宝贵的时间,一不留神复制少了一个数字还会导致数据错误;对手产品的销量则是由某一家咨询公司提供报告,每周一次,但是报告缺乏实时性,难以针对快速多变的市场及时调整价格和营销策略。
    学会一项新的技术
    第一方企业(也就是拥有这些数据的企业)做出更好的决策
    第三方企业也可从中受益
    数据共享
    Python:热门的开源软件(这意味着有人源源不断地开发更新且更强大的包给你用)
    Python:简单、简洁、易学、有效、可扩展性的计算机语言。 最受欢迎的程序语言之一。 强大而丰富的库。
    C语言:底层,学习成本大。

    1.2. 类型

    有哪些
  • 聚焦
  • 增量式

    1.3. 技能

    技能总览
    实现原理
    实现技术
    可以做什么
    开发技术
  • 三大库
  • 中间件(Middleware)、中间件的变化、中间件延伸
  • 提升速度、迅速技巧、倍速
  • 抓包与中间人
  • 定向爬取技术
    部署与计划运行
    攻防战
    Android原生App
    基于逆向分析小程序的
    常见搜索算法
    JSONAPl和AJAX

    1.4. 应用场景

    一些附加值更高的“事”,如人工智能、统计建模等。
    机器学习和统计算法分析
    在营销领域可以帮助企业做好4P(Product:产品创新,Place:智能选址,Price:动态价格,Promotion:数据驱动的营销活动)
    在金融领域,数据驱动的征信等应用会带来越来越大的价值。
    公开数据的应用价值
    所有网络数据
    社交媒体的每一条发帖。社交媒体在用户生态圈的自我交互下产生大量文本、图片和视频数据。
    团购网站的价格及点评。电商商产品的描述、价格
    招聘网站的招聘信息
    搜索引擎从数据库中提取搜索结果

    1.5. 流程图

    具体步骤及各步骤之间的关系。
    获【取】网页、解【析】网页(提取数据)、【存】储数据、整【理】。
  • 获取网页:给一个网址发送请求,该网址会返回整个网页的数据。类似于在浏览器中键入网址并按回车键,然后可以看到网站的整个页面。
  • 解析网页:从整个网页的数据中提取想要的数据。类似于在浏览器中看到网站的整个页面,但是你想找的是产品的价格,价格就是你想要的数据。
  • 存储数据:把数据存储下来。
    三个流程的技术实现:
  • 获取网页
    获取网页的基础技术:request、urllib和selenium(模拟浏览器)。
    获取网页的进阶技术:多进程多线程抓取、登录抓取、突破IP封禁和服务器抓取。
    并发编程(多线程(池)、多进程(池)、futures)
    异步编程(asyncio)
  • 解析网页
    解析网页的基础技术:re正则表达式、BeautifulSoup和lxml。
    解析网页的进阶技术:解决中文乱码。
  • 存储数据
    存储数据的基础技术:存入txt文件和存入csv文件。
    存储数据的进阶技术:存入MySQL数据库和存入MongoDB数据库。
    发起请求——通过HTTP库向⽬目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,等待服务器器响应。
    获取响应内容 ——如果服务器器能正常响应,会得到一个Response,Response的内容便便是所要获取的⻚页⾯面内容,类型可能有HTML,Json字符串串,二进制数据(如图⽚片视频)等类型。
    解析内容 ——得到的内容可能是HTML,可以⽤用正则表达式、⽹网⻚页解析库进⾏解析。可能是Json,可以直接转为Json对象解析,可能是二进制数据,可以做保存或者进一步的处理理。
    保存数据 ——保存形式多样,可以存为文本,也可以保存⾄至数据库,或者保存特定格式的文件。

    2. 获取网页

    2.1. 法律和道德、注意事项

    网络爬虫是否合法
    法律问题
    道德协议
    在充满爬虫的世界里做一个好公民
    用户爬虫的那些事儿
    是否合法
    基本议题
    成规模的爬虫一般都会使用集群,一般的小网站服务器规模可能不如爬虫集群的规模大。所以很多时候我们最好对要爬的网站限制一下频率。否则这些爬虫就相当于DoS攻击集群了!一般的网站都会有robots.txt可以参考。
    爬虫有哪些潜在的法律纠纷、公司的爬虫合不合法 。
    建立共利的互联网环境,不能把爬虫作为窃取数据的工具。
    爬虫必须在合情、合法、合理的情况下获取和应用。
    尊重数据供应者的知识产权和正常运作才能产生长久共利的环境。
    保障对方平台的正常运作是每个程序员都应当做到的
    法律:
    互联网世界已经通过自身的协议建立起一定的道德规范(Robots协议)。该协议是国际互联网界通行的道德规范,虽然没有写入法律,但是每一个爬虫都应该遵守这项协议。
    法律部分还在建立和完善中。
    如果抓取的数据属于个人使用或科研范畴,基本不存在问题。当你爬取网站数据时,无论是否仅供个人使用,都应该遵守Robots协议。
    而如果数据属于商业盈利范畴,就要就事而论,有可能属于违法行为,也有可能不违法。
    大部分网站不欢迎使用程序进行登录,因为需要登录才能查看的数据不属于公开数据。最好不要使用此程序获取非公开数据或批量注册,若出现了问题,可能需负法律责任。
    建议使用API。
    Robots协议
    Robots协议(爬虫协议)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
    https://www.taobao.com/robots.txt。
    Allow开头的URL是允许robot访问的。例如,Allow:/article允许百度爬虫引擎访问/article.htm、/article/12345.com等。
    Disallow不允许百度爬虫引擎访问的。例如,Disallow:/product/不允许百度爬虫引擎访问/product/12345.com等。
    Disallow:/禁止百度爬虫访问除了Allow规定页面外的其他所有页面。
    taobao的robots.txt对不同的搜索引擎所允许爬行范围不同。/product项对应淘宝内部的产品信息。当在搜索框中搜索“淘宝iphone7”的时候,Google可搜到淘宝中的产品,而百度不能。
    过于快速或者频密的网络爬虫都会对服务器产生巨大的压力。→调集资源限制爬虫,保护用户的流量和减少有价值数据的流失。
    反爬方维权:网站封锁你IP,法律行动。
    将请求的速度限定在一个合理的范围之内。
    每年的三月份会迎来一个爬虫高峰期。因为有大量的大学生五月份交论文,在写论文的时候会选择爬取数据,也就是3月份爬取数据,4月份分析数据,5月份交论文。
    2007年,爱帮网利用垂直搜索技术获取了大众点评网上的商户简介和消费者点评,并且直接大量使用,大众点评网多次要求爱帮网停止使用这些内容,而爱帮网以自己是使用垂直搜索获得的数据为由,拒绝停止抓取大众点评网上的内容,并且质疑大众点评网对这些内容所享有的著作权。为此,双方开打了两场官司。2011年1月,北京海淀法院做出判决:爱帮网侵犯大众点评网著作权成立,应当停止侵权并赔偿大众点评网经济损失和诉讼必要支出。
    2013年10月,百度诉360违反Robots协议。百度方面认为,360违反了Robots协议,擅自抓取、复制百度网站内容并生成快照向用户提供。2014年8月7日,北京市第一中级人民法院做出一审判决,法院认为被告奇虎360的行为违反了《反不正当竞争法》相关规定,应赔偿原告百度公司70万元。
    虽然说大众点评上的点评数据、百度知道的问答由用户创建而非企业,但是搭建平台需要投入运营、技术和人力成本,所以平台拥有对数据的所有权、使用权和分发权。【网站的知识产权】
    以上两起败诉告诉我们,在爬取网站的时候需要限制自己的爬虫,遵守Robots协议和约束网络爬虫程序的速度。如果违反了这些规定,很可能会吃官司,并且败诉的概率相当高。

    2.2. 网页特点

    静态网页:纯粹HTML格式的网页通常被称为静态网页。其在浏览器中展示的内容都在HTML源代码中。早期的网站一般都是由静态网页制作的。容易爬。
    动态网页:使用JavaScript、AJAX等技术展现的网页。很多内容并不会出现在HTML源代码中。主流网站一般都会使用。不容易爬。
    如何获取网页
  • 如何使用API获取数据【API是官方提供的数据获取通道,因此数据的获取是没有争议的。如果一个网站提供API获取数据,那么最好使用API获取,既简单又方便。】
  • 如何安装Requests库?如何使用Requests库获取响应内容(整个网页的源代码)
  • 基于深度和广度的爬虫。取深度加大到第3层,看看最短在多少秒之内能够完成前3层的爬虫。【深度优先的递归爬虫,广度优先的多线程爬虫】
  • 静态网页是啥
  • 动态网页是啥
  • 动态网页的实例
  • 什么是动态抓取?两种动态网页抓取技术获取动态网页的数据
    • 通过浏览器审查元素解析真实网页地址【AJAX动态解析地址】
    • 使用selenium模拟浏览器的方法

      2.2.1. 获取动态网页的真实地址

      Chrome浏览器的检查(审查元素)功能:浏览器右键⇒检查⇒Network⇒XHR或JS选项
      Network:显示浏览器从网页服务器中得到的所有文件。一般这些数据以json文件格式获取。
      在Network选项卡下,找到真正的评论文件。
      单击Preview标签即可查看数据。可以按 ctrl+F 进行查找。顶部search也可以。
      Elements会出现相应的code所在的地方。

      2.3. 抓包分析工具

      Fiddler
      什么是
      与爬虫的关系
      基本原理与基本界面
      捕获会话功能
      QuickExec命令行
      断点功能
      会话查找功能
      的其他功能

      2.4. API

      网站API分析
      使用
      秘钥获取
      数据获取

      2.5. 常用库

      Urllib库
  • 什么是
  • 快速使用
  • URLError异常处理
    requests
    BeautifulSoup4
    CSVFeedSpider
    强大的Requests库能够让你轻易地发送HTTP请求,这个库功能完善,而且操作非常简单

    2.6. requests

    http://cn.python-requests.org/zh_CN/latest/user/quickstart.html

chardet


import requests
import chardet
r = requests.get(‘http://www.baidu.com')
print(chardet.detect(r.content))
r.encoding = chardet.detect(r.content)[‘encoding’]
print(r.text)

import requests

# POST
postdata = {‘username’: ‘blog:qiyeboy’, ‘password’:1}
r = requests.post(‘http://www.xxxxxx.com/login', data=postdata)

# OTHERS
r = requests.put(‘http://www.xxxxxx.com/put', data = {‘key’:’value’})
r = requests.delete(‘http://www.xxxxxx.com/delete')
r = requests.head(‘http://www.xxxxxx.com/get')
r = requests.options(‘http://www.xxxxxx.com/get')

# 带参数的get【?&】:网址后面紧跟着“? ”, “? ”后面还有参数
payload = {‘Keywords’: ‘blog:qiyeboy’, ‘pageindex’:1}
r = requests.get(‘http://zzk.cnblogs.com/s/blogpost', params=payload)
print(r.url)

# 编码
r.content #返回字节
r.text #返回文本
r.encoding #根据HTTP头猜测的网页编码格式
r.encoding=’utf-8’ # 自行设置编码格式
print(r.text)

# 使用chardet confidence 检测精度
import chardet
print(chardet.detect(r.content)) # {‘encoding’: ‘utf-8’, ‘confidence’: 0.99, ‘language’: ‘’}
r.encoding = chardet.detect(r.content)[‘encoding’] #直接将chardet检测到的编码赋值给r.encoding后text就不会出现乱码

# 流模式

顺序page for循环
urllib.request.urlretrive()
信息过滤
唯一特殊标识
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import requests
r = requests.get('http://www.santostang.com/')
# ========【r的方法】========
# r response响应对象,存储了服务器响应的内容,以从中获取需要的信息
# r.encoding 服务器内容使用的文本编码。
# r.status_code 响应状态码。检测请求是否正确响应。
# r.text 字符串方式的响应体。会自动根据响应头部的字符编码进行解码。
# r.content 字节方式的响应体。会自动解码gzip和deflate编码的响应数据。gzip文件用这个。
# r.json() Requests中内置的JSON解码器。
# r.url r对应的请求的页面网址
# ========【requests.get的参数设置】========
## URL参数、请求头、发送POST请求、设置超时
## ----------【params】:dict ----------
### get传递url参数。http://httpbin.org/get?key1=value1&key2=value2
key_dict = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=key_dict)
## ----------【headers】:dict ----------
### 有的网站不带请求头会返回错误的数据。带请求头使程序更像人的手动行为
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36',
'Host': 'www.santostang.com'
}
r = requests.get('http://www.santostang.com/', headers=headers)
## ----------【data】: dict ----------
### 用于提交表单。data在发出请求的时候会自动编码为表单形式。
key_dict = {'key1': 'value1', 'key2': 'value2'}
r = requests.post('http://httpbin.org/post', data=key_dict)
## ----------【timeout】: 单位为秒 ----------
### 如果服务器在timeout秒内没有应答,就返回异常。一般会把这个值设置为20秒。
link = "http://www.santostang.com/"
r = requests.get(link, timeout= 0.001)
## 返回的异常为:
## ConnectTimeout: HTTPConnectionPool(host='www.santostang.com', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.HTTPConnection object at 0x00000000077806D8>, 'Connection to www.santostang.com timed out. (connect timeout=0.001)'))
## 异常值的意思是,时间限制在0.001秒内,连接到地址为www.santostang.com的时间已到。
# https://github.com/Santostang/PythonScraping/blob/master/第一版/Cha 3 -静态网页抓取/Cha 3 -静态网页抓取.ipynb

2.7. urllib

2.7.1. 核心代码

urllib2.urlopen(<>).read()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 核心代码
import urllib
import urllib2
## 请求1
response = urllib2.urlopen(<>)
## 请求2
values = {}
values['username'] = "XX"
values['password'] = "XXXX"
# 此三行等价于 values = {"username":"XX","password":"XXXX"}
data = urllib.urlencode(values)
request = urllib2.Request(url,data)
response = urllib2.urlopen(request)
# 读取
text = response.read()

2.7.2. eg.1 直接GET

1
2
3
import urllib2
response = urllib2.urlopen("http://www.baidu.com")
print response.read()

2.7.3. eg.2 带参数的GET

1
2
3
4
5
6
7
8
9
10
11
12
import urllib
import urllib2

values={}
values['username'] = "XX"
values['password']="XXXX"
data = urllib.urlencode(values)
url = "http://passport.csdn.net/account/login"
geturl = url + "?"+data
request = urllib2.Request(geturl)
response = urllib2.urlopen(request)
print response.read()

2.7.4. eg.3 POST

1
2
3
4
5
6
7
8
9
import urllib
import urllib2

values = {"username":"XX","password":"XXXX"}
data = urllib.urlencode(values)
url = "<post网址>"
request = urllib2.Request(url,data)
response = urllib2.urlopen(request)
print response.read()

2.7.5. 等效写法

1
2
3
4
# response = urllib2.urlopen("http://www.baidu.com")
request = urllib2.Request("http://www.baidu.com")
response = urllib2.urlopen(request)
# request对象,推荐写法,通过构建一个request,服务器响应请求得到应答,逻辑上清晰明确

2.7.6. 类方法解析

1
2
3
4
5
urlopen(url, data, timeout)
url,必选。
data,可选。默认为空None。访问URL时要传送的数据。
timeout,可选。默认为 socket._GLOBAL_DEFAULT_TIMEOUT。设置超时时间。
urlopen方法之后,返回一个response对象。

2.7.7. response

1
2
print response
<addinfourl at 139728495260376 whose fp = <socket._fileobject object at 0x7f1513fb3ad0>

2.7.8. 设置代理

proxy_handler = urllib2.ProxyHandler({"http" : 'http://some-proxy.com:8080'})
设置代理 ProxyHandler 参数为http字典
opener = urllib2.build_opener(proxy_handler)
打开代理 build_opener 参数为ProxyHandler
urllib2.install_opener(opener)

1
2
3
4
5
6
7
8
9
import urllib2
enable_proxy = True
proxy_handler = urllib2.ProxyHandler({"http" : 'http://some-proxy.com:8080'})
proxy_handler_null = urllib2.ProxyHandler({})
if enable_proxy:
opener = urllib2.build_opener(proxy_handler)
else:
opener = urllib2.build_opener(proxy_handler_null)
urllib2.install_opener(opener)

urllib2 默认会使用环境变量 http_proxy 来设置 HTTP Proxy。
有些网站会检测某一时间段内某个IP 的访问次数,如果访问次数过多,网站会禁止访问。
这时可以设置一些代理服务器来工作,每隔一段时间换一个代理。

2.7.9. 设置headers

request = urllib2.Request(url, data, headers)

1
2
3
4
5
headers = { 'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  , 
'Referer':'http://www.zhihu.com/articles' }
# 有些防盗链,服务器会识别headers中的referer是不是它自己,如果不是,服务器就不响应
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
headers = { 'User-Agent' : user_agent }

2.8. Selenium

Selenium模拟浏览器
Selenium和PhantomJS
Selenium和PhantomJS的配合使用
Selenium选择元素的方法有很多。
xpath和css_selector是比较好的方法,一方面比较清晰,另一方面相对其他方法定位元素比较准确。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
查找单个元素:
find_element_by_class_name:class选择
如<p class="content">Site content goes here.</p>⇒driver.find_element_by_class_name('content')。
find_element_by_css_selector:class选择
如<div class='bdy-inner'>test</div>⇒driver.find_element_by_css_selector ('div.bdy-inner')。
find_element_by_id:id选择
如<div id='bdy-inner'>test</div>⇒driver.find_element_by_id('bdy-inner')。
find_element_by_link_text:链接地址选择
如<a href="continue.html">Continue</a>⇒driver.find_element_by_link_text('Continue')。
find_element_by_name:name选择
如<input name="username"type="text" />⇒driver.find_element_by_name('username')。
find_element_by_partial_link_text:链接的部分地址选择
如 <a href="continue.html">Continue</a>⇒driver.find_element_by_partial_link_text('Conti')。
find_element_by_tag_name:名称选择
如<h1>Welcome</h1>⇒driver.find_element_by_tag_name('h1')。
find_element_by_xpath:通过xpath选择
如<form id="loginForm"> ⇒driver.find_element_by_xpath("//form[@id='loginForm']")。
查找多个元素时,[element]后加上s:
find_elements_by_class_name
find_elements_by_css_selector
find_elements_by_link_text
find_elements_by_name
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_xpath
除了Selenium的click操作元素方法,常见的操作元素方法:
● Clear清除元素的内容。
● send_keys模拟按键输入。
● Click单击元素。
● Submit提交表单。

comment = driver.find_element_by_css_selector(‘div.bdy-inner’)
content = comment.find_element_by_tag_name(‘p’)
Selenium的高级操作:

1
2
3
4
5
6
7
fp = webdriver.FirefoxProfile()
# 1. 限制CSS的页面
fp.set_preference("permissions.default.stylesheet",2)
# 2. 限制图片的显示。极大地提高网络爬虫的效率。图片文件相对于文字、CSS、JavaScript等文件都比较大,加载需要较长时间。
fp.set_preference("permissions.default.image",2)
# 3. 控制JavaScript的运行。大多数网页都会利用JavaScript异步加载很多内容,如果这些内容不是需要的,其加载会浪费时间。
fp.set_preference("javascript.enabled", False)

全部限制对于加载速度的提升效果最好。如果能够限制,那么最好限制多种加载,这样的效果最好。
具体的加载速度提升还得看相应的网页,若网页的图片比较多,则限制图片的加载肯定效果很好。
参考链接:selenium
Selenium官方文档:http://selenium-python.readthedocs.io/index.html。
Selenium要在整个网页加载出来后才开始爬取内容,速度往往较慢。
Selenium可以实现的功能:
操作元素对浏览器中的网页进行各种操作,包括登录。
模拟鼠标单击、双击、拖拽
获得网页中各个元素的大小
模拟键盘
浏览器渲染引擎。直接用浏览器在显示网页时解析HTML、应用CSS样式并执行JavaScript的语句。Selenium使用浏览器渲染,数据已经渲染到了HTML代码中。用chrome定位标签即可。
用脚本控制浏览器操作。Python的Selenium库模拟浏览器完成抓取。
Selenium:用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,浏览器自动按照脚本代码做出单击、输入、打开、验证等操作,就像真正的用户在操作一样。
用Selenium控制浏览器加载的内容,可加快Selenium的爬取速度。此类常用的方法有:
(1)控制CSS的加载。
(2)控制图片文件的显示。
(3)控制JavaScript的运行。
(1)控制CSS。因为抓取过程中仅仅抓取页面的内容,CSS样式文件是用来控制页面的外观和元素放置位置的,对内容并没有影响,所以我们可以限制网页加载CSS,从而减少抓取时间。
支持多个浏览器的调用:IE(7、8、9、10、11)、Firefox、Safari、Google Chrome、Opera等。最常用的是Firefox。

2.9. 爬虫与反爬

==术语==
网络爬虫:使用任何技术手段自动批量获取网站信息的一种方式。
反爬虫: 使用任何技术手段阻止批量获取网站信息的一种方式。
出书的人和经验丰富的实战工程师区别大概就在于此。
与爬虫的斗争
问题
为什么会被
方式有哪些、技术突破、如何“反反爬虫”
反爬虫(反爬虫会增加获取数据的难度。限制封锁。)与反反爬(初级的反反爬虫方法只能初步帮助我们顺利地完成爬虫程序)

  • 如登录后才可以查看【处理登录表单:使用Python登录表单。Selenium爬取网站】
  • 登录时设置验证码【处理验证码:通过程序识别图片中的文字(人工或者OCR)】
  • 如何保存cookies
  • 中文编码问题。为啥可以解决编码问题。为什么、怎么回事

    1
    2
    3
    4
    import sys
    sys.getdefaultencoding
    sys.getdefaultencoding()
    s.encoding('utf-8')
  • IP封锁与更换。【多服务器或Tor爬虫。如何让爬虫程序运行在“云”上,也能够让你随意改变自己的IP地址,进而走出爬虫被封IP的困境。】

  • 如何解决Python中文乱码的问题【什么是字符编码,Python的字符编码是什么】
    参考链接
    就像攻击武器与防御武器一样,双方总是在不断升级。爬虫和反爬是典型的攻防双方的互相升级。但这种升级不像军事,军事是无尽头的,但是爬虫和反爬是有尽头的。

    2.9.1. 爬虫的尽头

    就是浏览器,一旦使用浏览器,程序完全可以模拟真实用户发出请求,
    消耗资源,因为需要新开一个进程,解析DOM,运行客户端JavaScript代码。(chrome的node api在github开源仅仅两天,就拿到8k个star)

    2.9.2. 反爬的尽头

    就是像Google这种超级厉害的验证码,毕竟验证码的根本目的就是识别人类和机器的。

    2.9.3. 网站为什么要“反爬虫”

    第一,网络爬虫浪费网站的流量,也就是浪费钱。爬虫对于一个网站来说并不算是真正用户的流量,而且往往能够不知疲倦地爬取网站,更有甚者,使用分布式的多台机器爬虫,造成网站浏览量增高,浪费网站流量。
    第二,数据是每家公司非常宝贵的资源。在大数据时代,数据的价值越来越突出,很多公司都把它作为自己的战略资源。由于数据都是公开在互联网上的,如果竞争对手能够轻易获取数据,并使用这些数据采取针对性的策略,长此以往,就会导致公司竞争力的下降。
    因此,有实力的大公司便开始利用技术进行反爬虫,如淘宝、京东、携程等。反爬虫是指使用任何技术手段阻止别人批量获取自己网站信息的一种方式。
    再次特地声明,大家在获取数据时一定要有节制、有节操地爬虫。本书中的爬虫也仅用于学习、研究用途,请不要用于非法用途。任何由此引发的法律纠纷请自行负责。

    2.9.4. 爬虫与反爬一览

    反爬|应对
    –|–
    频率限制|随机sleep
    登陆限制|加上cookie
    header|header池
    JS|js反爬
    验证码|机器学习
    ip限制|代理池和高匿代理等好用的东西
    内容反爬|OCR
  • 反爬技术与反爬问题、网络异常
  • 负责爬虫技术攻坚,丰富爬虫反爬手段、反爬策略的设计及优化,快速解决
  • 设计爬虫策略和防屏蔽规则(常见的反爬手段及其应对措施=熟知当前各类反爬手段,对反爬机制有研究可破解(有能力解决复杂的反爬限制),有应对这些反爬手段的实际经验)
  • 登录爬取问题和验证码问题 解决办法和分析实例
    • JavaScript反爬
    • 验证码识别技术、复杂图片验证码、滑动块识验码、账号限制、ip限制
    • 优化爬虫路由调度策略
    • 对网站的cookie时效性处理有经验
  • 当在PC网页端爬取遇到困难时,爬取方式可以向手机网页端转变。

    2.9.5. 常见的反爬措施

    2.9.5.1. 浏览器伪装技术

    什么是
    准备工作
    Headers属性
    登录
    验证码
    表单交互
    需要登录的爬虫
    注册、登录及创建项目

    2.9.5.2. Cookie的使用

    2.9.5.3. 访问频率

    很好理解,如果访问太频繁网站可能针对你的ip封锁一段时间,这和防DDoS的原理一样。对于爬虫来说,碰到这样的限制一下任务的频率就可以了,可以尽量让爬虫想人类一样访问网页(比如随机sleep一段时间,如果每隔3s访问一次网站很显然不是正常人的行为)。

    2.9.5.4. 登录限制

    也比较常见。不过公开信息的网站一般不会有这个限制,这样让用户也麻烦了。其实反爬措施都或多或少的影响真实用户,反爬越严格,误杀用户的可能性也越高。对爬虫来说,登录同样可以通过模拟登录的方式解决,加个cookie就行了(话又说回来,网络的原理很重要)。

    2.9.5.5. 通过Header封杀

    一般浏览器访问网站会有header,比如Safari或者Chrome等等,还有操作系统信息。如果使用程序访问并不会有这样的header。破解也很简单,访问的时候加上header就行。

    2.9.5.6. JavaScript脚本动态获取网站数据

    有一些网站(尤其是单页面网站)的内容并不是通过服务器直接返回的,而是服务器只返回一个客户端JavaScript程序,然后JavaScript获取内容。更高级的是,JavaScript在本地计算一个token,然后拿这个token来进行AJAX获取内容。而本地的JavaScript又是经过代码混淆和加密的,这样我们做爬虫的通过看源代码几乎不可能模拟出来这个请求(主要是token不可能破解),但是我们可以从另一个角度:headless的浏览器,也就是我们直接运行这个客户端程序,这可以100%地模拟真实用户!

    2.9.5.7. 验证码

    这几乎是终极武器了,验证码是专门用来区分人和计算机的手段。对于反爬方来说,这种方式对真实用户和搜索引擎(其实可以通过记录搜索引擎爬虫的ip来区别对待,可以解决)的危害比较大,相信读者都有输入验证码的痛苦经历。但这种方法也并不是无敌的!通过现在很火的机器学习可以轻松的识别大部分的验证码!Google的reCAPTCHA是一种非常高级的验证码,但是听过通过模拟浏览器也是可以破解的。有的网站需要验证码验证拿到一个token,token长得很像一个时间戳,本地自己生成一个时间戳发现也是能用的!于是就这样绕过了验证码。

    2.9.5.8. ip限制

    网站可能将识别的ip永久封杀,这种方式需要的人力比较大,而且误伤用户的代价也很高。但是破解办法却非常简单。目前代理池几乎是搞爬虫的标配了,甚至还有很多高匿代理等好用的东西。所以这基本上只能杀杀小爬虫。

    2.9.5.9. 服务器采集

    代理服务器的设置
    为什么使用服务器采集
    使用动态IP拨号服务器
    使用Tor代理服务器

    2.9.5.10. 网站内容反爬

    有一些网站将网站内容用只有人类可以接收的形式来呈现(其实反爬就是区别对待人类和机器嘛)。比如将内容用图片的形式显示。但是近几年来人类和机器的差别越来越小,图片可以用OCR准确率非常高地去识别。
    网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本。
    爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛咯,如果它遇到资源,那么它就会抓取下来。想抓取什么?这个由你来控制它咯。
    比如它在抓取一个网页,在这个网中他发现了一条道路,其实就是指向网页的超链接,那么它就可以爬到另一张网上来获取数据。这样,整个连在一起的大网对这之蜘蛛来说触手可及,分分钟爬下来不是事儿。
    用户看到的网页实质是由 HTML 代码构成的,爬虫爬来的便是这些内容,通过分析和过滤这些 HTML 代码,实现对图片、文字等资源的获取。
    爬虫爬取数据时必须要有一个目标的URL才可以获取数据,因此,它是爬虫获取数据的基本依据,准确理解它的含义对爬虫学习有很大帮助。
    怎样扒网页呢?其实就是根据URL来获取它的网页信息,虽然我们在浏览器中看到的是一幅幅优美的画面,但是其实是由浏览器解释才呈现出来的,实质它是一段HTML代码,加 JS、CSS,如果把网页比作一个人,那么HTML便是他的骨架,JS便是他的肌肉,CSS便是它的衣服。所以最重要的部分是存在于HTML中的,下面我们就写个例子来扒一个网页下来。

    2.10. 编码

    什么是字符编码
    Python的字符编码
  • 文本、数字、bit、字节:计算机只能处理数字,文本转换为数字才能处理,
  • 字节:计算机中8个bit作为一个字节,一个字节能表示的最大数字就是255
  • ASCII: 计算机是美国人发明的,所以一个字节就可以标识所有单个字符,ASCII(一个字节)编码就成为美国人的标准编码
  • GB2312: 中文不止255个汉字,ASCII处理中文明显不够,所以中国制定了GB2312编码,用两个字节表示一个汉字。GB2312将ASCII也包含进去了。
  • Unicode:同理,日文,韩文,越来越多的国家为了解决这个问题就都发展了一套编码,标准越来越多,如果出现多种语言混合显示就一定会出现乱码
    • 于是unicode出现了,它将所有语言包含进去了。
  • “utf-8:可变长的编码。英文:1字节,汉字3字节,特别生僻的变成4-6字节。
    比较:
  • 如果内容全是英文,unicode编码比ASCII编码需要多一倍的存储空间,传输也会变慢。
  • 传输大量的英文,utf8作用就很明显。
    示例:
  • ASCII和unicode编码:
    • 字母A:ASCII编码十进制是65,二进制 0100 0001,unicode:00000000 0100 0001(编码只需要在二进制前面补0)
    • 汉字”中” 已近超出ASCII编码的范围,用unicode编码是20013二进制是01001110 00101101
      解决:
  • 读取文件,进行操作时转换为unicode编码进行处理
  • 保存文件时,转换为utf-8编码。以便于传输
  • 读文件的库会转换为unicode
    默认:
  • python2 默认编码格式为ASCII,
  • Python3 默认编码为 utf-8
    ython2 默认编码格式为 ASCII,Python3 默认编码为 utf-8

    2.11. 爬虫进阶

    怎么处理图片验证码
    反爬破解策略
    消息队列
    任务调度
    代理的使用
  • 用户代理池
  • IP代理池
  • 同时使用用户代理池与IP代理池的方法

    2.12. 异常处理

    为什么我抓到的和浏览器看到的不一样?怎样解决JavaScript渲染的问题
    分析Ajax请求、Selenium/WebDriver、PyV8、Ghost.py 、Splash

    3. 数据解析、清洗和组织

    直接处理、正则表达式、XPath、Json解析、BeautifulSoup、PyQuery
    难度:正则表达式>BeautifulSoup、lxml(可能在寻找正则表达式上耗费时间、BeautifulSoup的find方法很容易学)
    速度:BeautifulSoup≈lxml(BeautifulSoup已经支持lxml解析,因此速度和lxml差不多)
    XMLFeedSpider
    BeautifulSoup
    lxml
    JSON
    高性能HTML内容解析
    解析真实地址抓取
    解析数据
    如何解析网页上的数据。3种方法各有千秋,各自的优缺点
  • 解析JSON数据
  • BeautifulSoup解析网页
  • 正则表达式
  • BeautifulSoup(find方法)
  • XPath、lxml

BeautifulSoup
Urllib中使用XPath表达式
PhantomJS 、浏览器伪装
超时设置

3.1. bs4

使用BeautifulSoup解析网页
BeautifulSoup是一个工具箱。通过【解析文档】来提取数据。

  • 可以从HTML或XML文件中提取数据。
  • 可以提供一些简单的、Python式的函数用来处理导航、搜索、修改分析树等。
    简单,不需要多少代码就可以写出一个完整的应用程序。非常强大。
    支持Python标准库中的HTML解析器,还支持一些第三方的解析器。
    BeautifulSoup 4主要特性、适合做什么、怎样使用
    使用BeautifulSoup获取博客标题
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import requests
    from bs4 import BeautifulSoup
    link = "http://www.santostang.com/"
    headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
    r = requests.get(link, headers= headers)
    soup = BeautifulSoup(r.text,"html.parser") # 将网页响应体的字符串转化为soup对象
    # <h1>元素,class为' post-title',提取<a>元素中的文字,strip()的功能是把字符串左右的空格去掉。find只是用来找到第一条结果。
    first_title = soup.find("h1", class_="post-title").a.text.strip()
    print ("第一篇文章的标题是:", first_title)
    title_list = soup.find_all("h1", class_="post-title")
    for i in range(len(title_list)):
    title = title_list[i].a.text.strip()
    print ('第 %s 篇文章的标题是:%s' %(i+1, title))

找所有结果,用find_all。find_all返回列表。
BeautifulSoup的其他功能
soup.prettify() 代码美化
首先,需要把:

1
soup = BeautifulSoup(html, "html.parser")

代码转化成BeautifulSoup对象。
BeautifulSoup对象是一个复杂的【树】形结构,它的每一个【节点】都是一个【Python对象】。
提取对象的3种方法:

遍历文档树
搜索文档树
CSS选择器
1.遍历文档树
先爬树干,然后小树干,最后树枝。

1
2
3
4
5
6
soup.header.h3:获取取<h3>标签。如结果为:<h3 id="name">大数据@唐松Santos</h3>)。
soup.header.div.contents:列出某个标签的所有子节点。只能获取第一代子标签。
soup.header.div.contents[1]:索引为1的子标签。
soup.header.div.children:获得所有子标签。只能获取第一代子标签。
soup.header.div.descendants:获得所有子子孙孙标签
soup.header.div.a.parent:获得父节点的内容:

遍历文档树的方法其实使用得比较少。
2.搜索文档树
最常用的是搜索文档树。
最常用的是find()和find_all()。
find()和find_all()方法还可以和re正则结合起来使用

1
2
3
4
5
for tag in soup.find_all(re.compile("^h")):  # 找出所有以h开头的标签,这表示<header>和<h3>的标签都会被找到
print(tag.name)
# 输出的结果是:
# header
# h3

如果传入正则表达式作为参数,Beautiful Soup就会通过正则表达式的match()来匹配内容。

  1. CSS选择器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    通过tag标签逐层查找:soup.select("header h3")⇒得到的结果是:[<h3 id="name">大数据@唐松Santos</h3>]
    通过某个tag标签下的直接子标签遍历,:
    soup.select("header > h3") ⇒[<h3 id="name">大数据@唐松Santos</h3>]
    soup.select("div > a") ⇒ <div>下所有的< a>标签
    [<a href="http://www.santostang.com/feed/" rel="nofollow" target="_blank"title="RSS"><i aria-hidden="true" class="fa fa-rss"></i></a>, <a href="http://weibo.com/santostang" rel="nofollow" target="_blank" title="Weibo"><i aria-hidden="true" class="fa fa-weibo"></i></a>, …]
    soup.select('a[href^="http://www.santostang.com/"]'):找所有链接以http://www.santostang.com/开始的<a>标签
    得到的结果是:
    [<a href="http://www.santostang.com/feed/" rel="nofollow" target="_blank"title="RSS"><i aria-hidden="true" class="fa fa-rss"></i></a>,
    <a href="http://www.santostang.com/">首页</a>,
    <a href="http://www.santostang.com/about-me/">关于我</a>,
    <a href="http://www.santostang.com/post-search/">文章搜索</a>,
    <a href="http://www.santostang.com/wp-login.php">登录</a>]

5.3 使用lxml解析网页
一些比较流行的解析库
Xpath语法(如lxml),同样是效率比较高的解析方法。lxml使用C语言编写,解析速度比不使用lxml解析器的BeautifulSoup快一些。
5.3.2 使用lxml获取博客标题
使用lxml提取网页源代码数据的3种方法
XPath选择器
CSS选择器
BeautifulSoup的find()方法
和BeautifulSoup相比,lxml还多了一种XPath选择器方法。
XPath是一门在XML文档中查找信息的语言。
XPath使用路径表达式来选取XML文档中的节点或节点集,也可以用在HTML获取数据中。

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests
from lxml import etree
link = "http://www.santostang.com/"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers= headers)
html = etree.HTML(r.text) # 解析为lxml的格式
title_list = html.xpath('//h1[@class="post-title"]/a/text()') # 用XPath读取里面的内容
print (title_list)
//:无论在文档中什么位置
//h1:所有<h1>元素
//h1[@class="post-title"]:<h1>中class为"post-title"的元素
/a表示选取<h1>子元素的<a>元素
/text()表示提取<a>元素中的所有文本。

chrome审查,右键,选取元素,Copy→Copy XPath
5.3.3 XPath的选取方法
XPath使用路径表达式可以在网页源代码中选取节点,它是沿着路径来选取的,如表5-3所示。
XPath路径表达式及其描述 https://res.weread.qq.com/wrepub/epub_928559_47
下面是一个XML文档,我们将用XPath提取其中的一些数据。

1
2
3
4
5
6
7
8
9
<? xml version="1.0" encoding="ISO-8859-1"? >
<bookstore>
<book>
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>

XPath的一些路径表达式及其结果:https://res.weread.qq.com/wrepub/epub_928559_48
https://github.com/Santostang/PythonScraping/blob/master/%E7%AC%AC%E4%B8%80%E7%89%88/Cha%205%20-%E8%A7%A3%E6%9E%90%E7%BD%91%E9%A1%B5/Cha%205%20-%E8%A7%A3%E6%9E%90%E7%BD%91%E9%A1%B5.ipynb
5.5 BeautifulSoup爬虫实践:房屋价格数据
目的:获取安居客网站上北京二手房的数据。获取前10页二手房源的名称、价格、几房几厅、大小、建造年份、联系人、地址、标签。
网址:https://beijing.anjuke.com/sale/。
5.5.1 网站分析
5.5.2 项目实践
通过以上分析已经能够获得各个数据所在的地址,接下来用requests加上BeautifulSoup获取安居客北京二手房结果的第一页数据,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests
from bs4 import BeautifulSoup
import time
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36'}
for i in range(1,11):
link = 'https://beijing.anjuke.com/sale/p' + str(i)
r = requests.get(link, headers = headers)
print ('现在爬取的是第', i, '页')
soup = BeautifulSoup(r.text, 'lxml')
house_list = soup.find_all('li', class_="list-item")
for house in house_list:
name = house.find('div', class_ ='house-title').a.text.strip()
price = house.find('span', class_='price-det').text.strip()
price_area = house.find('span', class_='unit-price').text.strip()
no_room = house.find('div', class_='details-item').span.text
area = house.find('div', class_='details-item').contents[3].text
floor = house.find('div', class_='details-item').contents[5].text
year = house.find('div', class_='details-item').contents[7].text
broker = house.find('span', class_='brokername').text
broker = broker[1:]
address = house.find('span', class_='comm-address').text.strip()
address = address.replace('\xa0\xa0\n ',' ')
tag_list = house.find_all('span', class_='item-tags')
tags = [i.text for i in tag_list]
print (name, price, price_area, no_room, area, floor, year, broker, address, tags)
time.sleep(5)

进阶:获取其中的各项数据,如小区名称、房屋类型、房屋朝向、参考首付等。
https://github.com/Santostang/PythonScraping/blob/master/%E7%AC%AC%E4%B8%80%E7%89%88/Cha%205%20-%E8%A7%A3%E6%9E%90%E7%BD%91%E9%A1%B5/Cha%205%20_%E7%AB%A0%E6%9C%AB%E5%AE%9E%E6%88%98.ipynb

3.2. Xpath

xpath语法
表达式|说明|
–|–|
article|选取所有article元素的所有子节点|
/article|选取根元素article|
article/a|选取所有属于article的子元素的a元素|
//div|选取所有div元素(不管出现在文档里的任何地方)|
article//div|选取所有属于article元素的后代的div元素,不管它出现在article之下的任何位置|
/div/|选取属于div元素的所有子节点|
//
|选取所有元素|
//div[@*]|选取所有带属性的div 元素|
//@class|选取所有名为class的属性|
//div/a 丨//div/p|选取所有div元素的a和p元素|
//span丨//ul|选取文档中的span和ul元素|
article/div/p丨//span|选取所有属于article元素的div元素的p元素以及文档中所有的 span元素
xpath语法-谓语:
表达式|说明|
–|–|
/article/div[1]|选取属于article子元素的第一个div元素|
/article/div[last()]|选取属于article子元素的最后一个div元素|
/article/div[last()-1]|选取属于article子元素的倒数第二个div元素|
//div[@color]|选取所有拥有color属性的div元素|
//div[@color=’red’]|选取所有color属性值为red的div元素|
xpath的使用
会右键查看就能获取网页上任何内容

  1. xpath简介
  2. xpath术语与语法
  3. xpath抓取误区:javasrcipt生成html与html源文件的区别
  4. xpath抓取实例
    为什么要使用xpath?
    xpath使用路径表达式在xml和html中进行导航
    xpath包含有一个标准函数库
    xpath是一个w3c的标准
    xpath速度要远远超beautifulsoup。
    xpath节点关系
    父节点、上一层节点
    子节点
    兄弟节点、同胞节点
    先辈节点、父节点、爷爷节点
    后代节点、儿子、孙子
    xpath抓取误区
    firebugs插件
    取某一个网页上元素的xpath地址
    如:http://blog.jobbole.com/110287/
    在标题处右键使用firebugs查看元素。
    然后在

    2016 腾讯软件开发面试题(部分)

    右键查看xpath

    3.3. 解析器对比分析

    主要的解析器及其优缺点
    https://res.weread.qq.com/wrepub/epub_928559_44
    https://res.weread.qq.com/wrepub/epub_928559_49
    使用lxml的解析器将会解析得更快。

    4. 数据存储

    数据存储
    方式
  • TXT
  • CSV
  • Excel
  • JSON
  • MySQL
  • MongoDB及其优化建议
    如何存储数据
  • 存TXT。【写入和读取都非常方便,可以很快速地打开文件查看。用来存储测试用的数据。文件大时打开很慢。数据修改麻烦】
  • 存CSV。【同上】
  • 存MySQL。【数据量比较大、要与别人交换或别人也要访问时】
  • 存MongoDB。【同上。JSON格式数据而不用进行解析】
    文本——纯文本、Json、Xml等。
    二进制文件——如图片、视频、⾳频等直接保存成特定格式即可。
    关系型数据库——如MySQL、Oracle、SQL Server等具有结构化表结构形式存储。
    非关系型数据库——如MongoDB、Redis等Key-Value形式存储。

    4.1. 数据库

    创建、连接和查询
    数据导入
    Python3操作
    与标准Python客户端建立数据库接口
    数据库设计
  • oracle、Cassandra
  • 熟悉关系型(mysql/postgresql)、nosql(mongodb/hbase/elasticsearch/HBase/HIVE)、缓存sql(redis/memcached)
  • 调优和海量存储经验优先;能进行简单优化 有大数据开发经验优先 熟悉hadoop、spark、storm
  • 至少精通大数据量的一种关系型开发
  • 三种数据库的存储方式、SQLite、MySQL和MongoDB三种数据库的操作方式,实现爬取数据存储的多样化
    MySQL
    MongoDB
    Redis
    SQLite
    Excel表格自动合并
    ‘’’⽹页文本’’’——如HTML文档、Json格式文本等。
    ‘’’图⽚’’’——获取到的是二进制文件,保存为图片格式。
    ‘’’视频’’’——同为二进制文件,保存为视频格式即可。
    ‘’’其他’’’——只要是能请求到的,都能获取。

    5. 高性能爬取策略

    基础爬虫
    简单分布式爬虫
    Scrapy爬虫
    Scrapy分布式爬虫
    深度优先的递归
    广度优先
    定向爬取
    爬虫的浏览器伪装技术
    HTTP协议请求
    DebugLog
    异常处理神器——URLError
    Cookiejar精析
    并发和并行,同步和异步、异步加载技术与爬虫方法、多协程、多线程、多进程
    如何提升爬虫的速度效率(速度实现成倍提升)。比较。
    二叉树的遍历问题
    深度优先(递归实现)
    顺着一条路,走到最深处。然后回头。垂直方向
    广度优先(队列实现)
    分层遍历:遍历完儿子辈。然后遍历孙子辈。水平方向
    深度优先算法
1
2
3
4
5
6
7
def depth_tree(tree_node):
if tree_node is not None:
print (tree_node._data)
if tree_node._left is not None:
return depth_tree(tree_node.left)
if tree_node._right is not None:
return depth_tree(tree_node._right)

广度优先算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def level_queue(root):
#利用队列实现树的广度优先遍历
if root is None:
return
my_queue = []
node = root
my_queue.append(node)
while my_queue:
node = my_queue.pop(0)
print (node.elem)
if node.lchild is not None:
my_queue.append(node.lchild)
if node.rchild is not None:
my_queue.append(node.rchild)

5.1. 性能

标准性能模型
解决性能问题
系统性能
示例1:非常简单的管道
示例2:测量吞吐量和延时的扩展
超时设置
容错处理
定时爬取
自动化爬取的重要性
定向爬取的相关步骤与策略
动态渲染页面的爬取、JavaScript与AJAX数据爬取
简单的矩形区域抓取方式
高级区域抓取方式
创建自定义监控命令
使用ApacheSpark流计算偏移量

6. Scrapy分布式爬虫

好(较为成熟)的爬虫方案:多X程、分布式、将爬虫部署在服务器上把自己的个人计算机解放出来
如何通过Redis实现了一个分布式爬虫,让其在不同服务器之间通信。
分布式爬虫的好处是什么?

  • 队列的分配是依靠master的,当你获取数据的某一台slave奴隶服务器因为各种原因停止爬虫了,也不会让整个爬虫程序停下来。
  • 分布式爬虫既可成倍提升爬虫效率,又可保证爬虫的稳定性。
  • (1)服务器之间有通信,每个服务器的待爬网页无需手动分配。
  • (2)数据集中存储到某一个服务器或数据库中。统一管理能够实现从不同服务器爬虫的队列管理到数据存储的优化。
    Scrapy框架的安装
    Scrapy框架基本使用
    Scrapy命令行详解
    Scrapy中选择器的用法
    Scrapy中Spiders的用法
    Scrapy中Item Pipeline的用法
    Scrapy中Download Middleware的用法
    Scrapy爬取知乎用户信息实战
    Scrapy+Cookies池抓取新浪微博
    Scrapy+Tushare爬取微博股票数据
    命令行创建scrapy项目
    cd desktop
    scrapy startproject ArticleSpider
    scrapy目录结构
    scrapy借鉴了django的项目思想
    scrapy.cfg:配置文件。
    setings.py:设置
    SPIDER_MODULES = [‘ArticleSpider.spiders’] #存放spider的路径
    NEWSPIDER_MODULE = ‘ArticleSpider.spiders’
    pipelines.py: 数据存储相关
    middilewares.py: 自己定义的middlewares 定义方法,处理响应的IO操作
    init.py:项目的初始化文件。
    items.py:定义我们所要爬取的信息的相关属性。Item对象是种类似于表单,用来保存获取到的数据
    创建spider
    cd ArticleSpider
    scrapy genspider jobbole blog.jobbole.com
    自动生成
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    -*- coding: utf-8 -*-
    import scrapy
    class JobboleSpider(scrapy.Spider):
    name = "jobbole"
    allowed_domains = ["blog.jobbole.com"]
    # start_urls是一个带爬的列表,
    #spider会为我们把请求下载网页做到,直接到parse阶段
    start_urls = ['http://blog.jobbole.com/']
    def parse(self, response):
    pass

在命令行启动Spider
scrapy crawl jobbole
创建调试工具类
在项目根目录里创建main.py作为调试工具文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# _*_ coding: utf-8 _*_
#
__author__ = 'mtianyan'
__date__ = '2017/3/28 12:06'
#
import sys
import os
from scrapy.cmdline import execute
#
# 将系统当前目录设置为项目根目录
# os.path.abspath(__file__)为当前文件所在绝对路径
# os.path.dirname为文件所在目录
# H:\CodePath\spider\ArticleSpider\main.py
# H:\CodePath\spider\ArticleSpider
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# 执行命令,相当于在控制台cmd输入改名了
execute(["scrapy", "crawl" , "jobbole"])

设置不遵守reboots协议
settings.py的
ROBOTSTXT_OBEY = False
⭕在jobble.py打上断点
def parse(self, response):
pass
返回的htmlresponse对象:
body:网页内容
_DEFAULT_ENCODING= ‘ascii’
encoding= ‘utf-8’
scrapy已经为我们做到了将网页下载下来。而且编码也进行了转换.
import scrapy
class JobboleSpider(scrapy.Spider):
name = “jobbole”
allowed_domains = [“blog.jobbole.com”]
start_urls = [‘http://blog.jobbole.com/110287/']
def parse(self, response):
re_selector = response.xpath(“/html/body/div[3]/div[3]/div[1]/div[1]/h1”)

# print(re_selector)
pass

调试debug可以看到
re_selector =(selectorlist)[]
可以看到返回的是一个空列表,
列表是为了如果我们当前的xpath路径下还有层级目录时可以进行选取
空说明没取到值:

//*[@id=”post-110287”]/div[1]/h1

1
2
3
4
5
6
7
8
9
import scrapy
class JobboleSpider(scrapy.Spider):
name = "jobbole"
allowed_domains = ["blog.jobbole.com"]
start_urls = ['http://blog.jobbole.com/110287/']
def parse(self, response):
re_selector = response.xpath('//*[@id="post-110287"]/div[1]/h1')
# print(re_selector)
pass

6.1. 概述

分布式系统概述
初识Scrapy Scrapy是一个Twisted应用
喜欢Scrapy的更多理由
Scrapy不是什么
框架介绍、架构概述、核心架构
目录结构
Scrapy设置
常用的Scrapy组件详解
Scrapy工作流
Scrapy引擎——一种直观方式
Scrapy高级应用
理解Scrapy性能

6.2. 部署到Scrapinghub

搜索引擎核心
爬行策略
网页更新策略
身份识别
什么是Cookie
常用工具命令
Spider类参数传递
避免被禁止
UR2lM——基本抓取流程
抽取更多的URL
创建手机应用
访问item
配置与管理
基本设置
进阶设置
信号
管道秘诀
使用RESTAPl
使用Twisted专用客户端建立服务接口
为CPU密集型、阻塞或遗留功能建立接口
使用telnet获得组件利用率
基准系统
故障排除流程

6.3. 代码

items的编写
pipelines的编写
settings的编写
Items的编写
Spider的编写

6.4. 使用Scrapy填充数据库

Scrapy的中文输出
Scrapy的中文存储
Scrapy与MongoDB
Scrapy与Redis

6.5. Scrapyd

分布式爬虫与Scrapy
Scrapyd部署分布式爬虫
Scrapyd与实时分析进行分布式爬取

6.6. Scrapy项目

用Scrapy进行爬虫项目管理
Scrapy爬虫多开技能
从Scrapy到移动应用
财经新闻数据
博客
Redis分布式爬虫实践
认识框架
框架安装难点解决技巧
常见指令
使用
You-get源码分析
与Urllib的整合
多线程
分布式
https://github.com/LUCY78765580/Python-web-scraping
https://github.com/qiyeboy/SpiderBook
分布式爬虫的架构解析
分布式爬虫实现原理
分布式爬虫之Docker基础
分布式爬虫之Redis基础
分布式爬虫构建实战
Scrapy分布式原理及Scrapy-Redis源码解析
Scrapy分布式架构搭建抓取知乎
Scrapy分布式的部署详解
小白爬虫第一弹之抓取妹子图
小白爬虫第二弹之健壮的小爬虫
小白爬虫第三弹之去重去重
小白爬虫第四弹之爬虫快跑(多进程+多线程)
小白进阶之Scrapy第一篇
小白进阶之Scrapy第二篇(登录篇)
小白进阶之Scrapy分布式的前篇–让redis和MongoDB安全点
小白进阶之Scrapy第三篇(基于Scrapy-Redis的分布式以及cookies池)
小白进阶之Scrapy第四篇(图片下载管道篇)
小白进阶之Scrapy第五篇(Scrapy-Splash配合CrawlSpider;瞎几把整的)
利用新接口抓取微信公众号的所有文章
小白进阶之Scrapy第六篇Scrapy-Redis详解
https://www.jianshu.com/p/cd4054bbc757
https://cloud.tencent.com/developer/article/1114535
爬虫只运行在一台机器上时,受计算能力和网络带宽的影响,即使使用了异步和多线程技术,在待爬数据量较大时,需要耗费的时间会比较长,爬取效率也非常有限。
而多台主机协同爬取,效率会成倍增加。此即为分布式爬取,在网络中的多台计算机上同时运行爬虫程序,共同完成一个大型爬取任务。
Scrapy本身并不是一个为分布式爬取而设计的框架,但第三方库scrapy-redis为其拓展了分布式爬取的功能,两者结合便是一个分布式Scrapy爬虫框架。
在分布式爬虫框架中,需要使用某种通信机制协调各个爬虫的工作,让每一个爬虫明确自己的任务,其中包括:
(1)当前的爬取任务,即下载+提取数据(分配任务)。
(2)当前爬取任务是否已经被其他爬虫执行过(任务去重)。
(3)如何存储爬取到的数据(数据存储)。
scrapy-redis利用Redis数据库作为多个爬虫的数据共享实现以上功能。
网站的树结构(url分层设计)
网站url树结构分层设计:
bogbole.com
blog.bogbole.com
python.bogbole.com
python.bogbole.com/123
去重问题与策略
环路链接问题
从首页到下面节点。
但是下面的链接节点又会有链接指向首页。
有些已经爬过
将访问过的url保存到数据库中
将url保存到set中。只需要O(1)的代价就可以查询到url

1000000002byte50个字符/1024/1024/1024 = 9G
url经过md5等方法哈希后保存到set中,将url压缩到固定长度而且不重复
用bitmap方法,将访问过的url通过hash函数映射到某一位
bloomfilter方法对bitmap进行改进,多重hash函数降低冲突(scrapy去重,分布式scrapy-redis)
基于Hadoop的分布式网络爬虫系统的设计与实现

7. 数据分析

7.1. 可视化

地图
轨迹

7.2. NumPy

一维数组
多维数组
数组的运算

7.3. pandas

数据清洗
数据分组、分割、合并和变形
缺失值、异常值和重复值处理
时序数据处理
数据类型转换

8. 框架

爬虫架构设计
爬虫框架
什么是
常见的

  • CrawlSpider与链接提取器、CrawlSpider实例
  • Crawley
  • Portia
  • newspaper
  • Python-goose
  • PySpider
    手机应用框架
    PySpider框架基本使用及抓取TripAdvisor实战
    PySpider架构概述及用法详解
    PyQuery详解
    Selenium详解

    9. 项目实施

    熟练掌握一种开源爬虫工具,有研发爬虫框架经验者优先;scrapy、webmagic、nutch、heritrix、Requests、Selenium、Appium、PhantomS
  • 著名爬虫框架Scrapy的运用、
  • 通过Redis和Scrapy的结合实现分布式爬虫
  • 整个的实现过程以及注意事项
  • PySpider(基本功能)
    熟悉HttpClient、HtmlParser、Jsoup、Lucene、Nutch中的一种或多种开源技术
    研究各种网页特点和规律
    项目描述
    功能分析
    实现思路
    网站分析
    编写实战
    调试与运行
    项目实施
    优化方案
    代码优化
    效率优化
    网页分析算法
    数据来源分析
    工作流程
    通过热力图分析为用户提供出行建议
    从数据到产品
    产品设计
    产品交付
    数据获取渠道
    发现数据的价值
    pyecharts业服务
    从价值探索到交付落地
    创新的不确定性
    房产的标题是如何影响价格的
    通过 2 个爬虫免试获得 2 个业界知名公司 offer
  • 具备一个爬虫开发工程师需要的全部技能
  • 理论性、经验性的内容为主,远远无法达到一个系统的标准
  • 完整的爬虫开发需要学习的知识的体系
  • 在过去的工作中完成过上百个抓取任务
  • 参与和维护着使用 Celery、Twisted 等技术完成每天上亿次抓取量的抓取服务
  • 3个写爬虫实现功能的视频
  • 17年4月在知乎开过一场叫做 爬虫从入门到进阶 的知乎Live,目前已经有3.3k+人参加,评分4.9分(满分5分)

    9.1. 框架搭建

    架构设计、系统规划、建立、开发、研发、维护(完善)与管理、日常监控、优化、建模、调研
    爬虫系统的架构设
  • 精通信息抓取抽取技术和整合技术、抽取算法保证抽取、去重、分类、解析、增量融合入库等流程之后的数据结果;内容提取
    • 网页去重 、大规模爬取中的去重问题 、海量数据的去重方式以及各种去重方式的优劣比较
  • 网页信息调度、采集抓取提取、维护、验证、抓取规划、解析、清洗、入库以及汇总、清洗、整理、整合及合并、有数据分析能力。研发和优化工作
  • 分布式网络爬虫、高并发、高可用爬虫平台架构的设计和优化
  • 爬虫系统与数据分析系统数据接口设计和开发
  • 高性能爬虫系统的后台监控、报警模块的开发
  • 爬虫引擎核心功能
  • 能快速部署新的爬虫应用
    • 多线程、多进程、协程相关知识及编程经验 、网路编程以及Web认证机制
    • 分布式、
    • 抓取调度,多样化抓取,页面解析和结构化抽取,海量数据存储和读取、实时高并发海量数据爬取
  • 核心算法的策略优化:充分利用资源,避免限制;
    • 模板提高扩展性、效率和质量、持续优化系统提高系统的稳定性、监控抓取数据的完整性
    • 调权调度、分析预测、质量判断、封禁与反封禁研究
  • 备份

    9.2. 扩展技能

    熟悉搜索引擎、有搜索开发经验加分、优化搜索、匹配、抓取等关键程序的性能及效率
    有网站开发经历加分、web挖掘能力
    挖掘算法优化
    数据分类及分布统计,文本分类、统计分析
    特征挖掘。具有数据挖掘、自然语言处理、信息检索
    个性化相关的机器学习算法、精通主流分词算法、分类、提取摘要、大规模网页聚类、索引等相关开发经验者优先。
    有客户端及相关安全领域经验者优先

    9.3. 后起

    网页外挂机器人开发及维护
    进行技术分享与培训
    网页数据的自动化爬取脚本
    数据爬取平台相关工具平台的架构设计与产品开发
    参与数据层建设,专注于基础数据采集平台建设
    爬取10w量级的数据
    统计分析、可视化展示,发掘数据价值 【彩色直方图、折线图】
    Django展示数据图
    多平台信息的抓取和分析

    9.4. 加分项目

    垂直领域数据 社交、新闻媒体、论坛类、商业大数据、金融证券行业
    网络数据源
  • 网站(页):电商网站、定期爬取指定网站(如亚马逊、ebay平台)的数据、有大型B2C、C2C电商网站
  • APP
    1,项目的目标。【爬取知乎Live的所有实时语音分享以及知乎Live的听众。知乎Live的URL地址为https://www.zhihu.com/lives】
    2.列举出各项目所采用的技术。
    3.初始Url
    4.项目步骤
  • 一个简单的Python网络爬虫
  • 维基百科
    • 维基百科是一个网络百科全书,在一般情况下允许用户编辑任何条目。当前维基百科由非营利组织维基媒体基金会负责营运。维基百科一词是由网站核心技术Wiki和具有百科全书之意的encyclopedia共同创造出来的新混合词Wikipedia。
  • 大众点评
  • (1)通过大众点评的搜索结果获取餐厅的基本信息和地址。
  • (2)进入每家店铺的网页,获取大众点评餐厅的详细信息和评价。
  • 百度地图API
    • http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi
    • 获取中国所有城市的公园数据,并且获取每一个公园具体的评分、描述等详情,最终将数据存储到MySQL数据库中。
    • 拥有丰富的餐馆、房地产等数据,是一款网络地图搜索服务。可查地理位置,最近位置。街道、商场、楼盘、餐馆、学校、银行、公园等。百度地图提供了丰富的API供开发者调用,我们可以免费地获取各类地点的具体信息。
    • 免费API:新浪微博、豆瓣电影、饿了么、豆瓣音乐、Facebook、Twitter。
    • 收费API:百度API Store、聚合数据
  • 知乎
    • 知乎是中文互联网一个非常大的知识社交平台。在知乎上,用户可以通过问答等交流方式获取知识。区别于百度知道等问答网站,知乎的回答往往非常深入,都是回答者精心写的,知乎上聚集了中国互联网科技、商业、文化等领域里最具创造力的人群,将高质量的内容通过人的节点形成规模的生产和分享,构建高价值人际关系网络。
  • 爬取了博客文章评论

    10. 实际爬虫

    Requests+正则表达式
    分析Ajax请求
    使用Selenium模拟浏览器
    使用Redis+Flask
    房产
    基于位置信息的Ⅰ
    猫眼电影
    今日头条街拍美图
    淘宝商品美食信息
    维护动态代理池
    维护动态Cookies池
    使用代理处理反爬抓取微信文章
    图片
    链接
    糗事百科
    微信
    博客类
    图片类
    模拟登录
    抢票软件的实现
    PEXELS图片
    糗事百科网的用户地址信息
    豆瓣音乐TOP250的数据
    豆瓣电影TOP250的数据
    豆瓣网图书TOP250的数据
    维基百科
    餐厅点评
    知乎Live
    百度地图API
    畅销书籍
    TOP250电影数据
    房屋价格数据
    虎扑论坛
    酷狗TOP500的数据
    知乎网Python精华话题
    简书网热门专题信息
    简书网专题收录文章
    简书网推荐信息
    简书网热评文章
    简书网用户动态信息
    简书网7日热门信息
    拉勾网招聘信息
    起点中文网小说信息
    《斗破苍穹》全文小说
    新浪微博好友圈信息
    QQ空间好友说说
    转转网二手市场商品信息
    淘宝商品信息
    北京地区短租房信息
    糗事百科网的段子信息
    电商网站(商品)数据——大型爬虫(Selenium)
    BOSS直聘爬虫
    Keep热门
    果壳网自动登录
    大麦网演出
    小说网
    博客
    猜数游戏半自动爬虫开发
    股票行情(用Scrapy)
    深圳短租数据(Selenium)
    用API爬取天气预报数据
    知乎(asyncio)
    新浪微博
    京东
    淘宝
    出版社信息
    京东图书
    当当网
    新闻
    豆瓣网登陆爬虫与验证码自动识别
    模拟登录
    腾讯动漫(JS动态触发+id随机生成反爬破解实战)
    微信爬虫
    腾讯视频评论爬虫思路介绍
    腾讯视频评论爬虫实战
    糗事百科
    抓包分析实战
    tt商品图片爬虫实战
    tt商品大型爬虫项目与自动写入数据库实战)
    作业讲解:博文信息的爬取
    腾讯微信和视频
    百度信息自动搜索
    自动POST

    10.0.1. 简单的爬虫

    【用到的库】requests + bs4
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # https://github.com/Santostang/PythonScraping/blob/master/第一版/Cha 2 - 编写你的第一个网络爬虫/Cha 2 _章末实战.ipynb
    #!/usr/bin/python
    # coding: utf-8
    import requests
    from bs4 import BeautifulSoup #从bs4这个库中导入BeautifulSoup
    # 第一步:获取页面
    link = "http://www.santostang.com/"
    headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
    r = requests.get(link, headers= headers) # requests的headers伪装成浏览器访问。r是requests的Response回复对象。
    # 第二步:提取需要的数据
    soup = BeautifulSoup(r.text, "html.parser") # 使用BeautifulSoup解析这段网页。把HTML代码转化为soup对象。r.text是获取的网页内容代码
    title = soup.find("h1", class_="post-title").a.text.strip() # 提取第一篇文章的标题
    print (title)
    # 第三步:存储数据
    with open('title_test.txt', "a+") as f:
    f.write(title)

10.0.2. 爬取豆瓣电影TOP250

【用到的库】requests + bs4
获取豆瓣电影TOP250的所有电影的名称
网页地址为:https://movie.douban.com/top250
第一页有25个电影
获取所有的250页电影
总共10页的内容
第二页:https://movie.douban.com/top250? start=25
第三页:https://movie.douban.com/top250? start=50

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests
from bs4 import BeautifulSoup
def get_movies():
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36',
'Host': 'movie.douban.com'
}
movie_list = []
for i in range(0,10):
link = 'https://movie.douban.com/top250?start=' + str(i * 25)
r = requests.get(link, headers=headers, timeout= 10)
print (str(i+1),"页响应状态码:", r.status_code)

soup = BeautifulSoup(r.text, "lxml")
div_list = soup.find_all('div', class_='hd')
for each in div_list:
movie = each.a.span.text.strip()
movie_list.append(movie)
return movie_list

movies = get_movies()
print (movies)
# 原文有误
# 用 ]: 便于在 ipynb 中查找下一项

参考链接:豆瓣电影(https://github.com/Santostang/PythonScraping/blob/master/第一版/Cha 3 -静态网页抓取/Cha 3 _章末实战.ipy)
进阶问题:获取TOP 250电影的英文名、港台名、导演、主演、上映年份、电影分类以及评分。

10.0.3. 爬取动态网页

【用到的库】requests + json
AJAX加载的动态网页,有两种爬取方法:
(1)通过浏览器审查元素解析地址。
(2)通过Selenium模拟浏览器抓取。
两个特别重要的变量,即offset和limit。
limit:每一页评论数量的最大值
offset:本页的第一条评论是总的第几条

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
import json
def single_page_comment(link):
headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers= headers)
# 获取 json 的 string
json_string = r.text
json_string = json_string[json_string.find('{'):-2]
json_data = json.loads(json_string) # 使用json.loads()把字符串格式的响应体数据转化为json数据
comment_list = json_data['results']['parents'] # json数据的结构提取
for eachone in comment_list:
message = eachone['content']
print (message)
for page in range(1,4):
link1 = "https://api-zero.livere.com/v1/comments/list?callback=jQuery112407875296433383039_1506267778283&limit=10&offset="
link2 = "&repSeq=3871836&requestPath=%2Fv1%2Fcomments%2Flist&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&_=1506267778285"
page_str = str(page)
link = link1 + page_str + link2
print (link)
single_page_comment(link)

参考链接:
https://github.com/Santostang/PythonScraping/blob/master/第一版/Cha 4 -动态网页抓取/Cha 4 -动态网页抓取.ipynb

10.0.4. 通过Selenium模拟浏览器抓取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("https://www.dianping.com/search/category/7/10/p1")
# 如果运行之后,发现程序报错:
# selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.
# 可以到https://github.com/mozilla/geckodriver/releases下载最新版的geckodriver,解压后可以放在Python安装目录(可能是Script子文件夹)下(可能需并放在环境变量的PATH中)。
from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
caps = webdriver.DesiredCapabilities().FIREFOX
caps["marionette"] = False

path = r'D:\\Program Files\\Mozilla Firefox\\firefox.exe'
binary = FirefoxBinary(path) # Firefox程序的地址
driver = webdriver.Firefox(firefox_binary=binary, capabilities=caps)
driver.get("http://www.santostang.com/2017/03/02/hello-world/")
import time
try:
load_more = driver.find_element_by_css_selector('div.tie-load-more') # 更多或下一页
load_more.click() # 模拟单击
except:
pass
comments = driver.find_elements_by_css_selector('div.bdy- inner')
time.sleep(5)
user = driver.find_element_by_name("username") #找到用户名输入框
user.clear #清除用户名输入框内容
user.send_keys("1234567") #在框中输入用户名
pwd = driver.find_element_by_name("password") #找到密码输入框
pwd.clear #清除密码输入框内容
pwd.send_keys("******") #在框中输入密码
driver.find_element_by_id("loginBtn").click() #单击登录

10.0.5. 深圳短租

目的:获取Airbnb深圳前20页的短租房源的名称、价格、评价数量、房屋类型、床数量和房客数量。监控和了解竞争对手的房屋名称和价格,让自己的房子有竞争力。
网址:https://zh.airbnb.com/s/Shenzhen--China?page=1
4.4.1 网站分析
一个房子的所有数据。地址为:div.infoContainer_v72lrv。
价格数据,地址为:div.priceContainer_4ml1ll
评价数据,地址为:span.text_5mbkop-o_O-size_micro_16wifzf-o_O-inline_g86r3e
房屋名称数据,地址为:div.listingNameContainer_kq7ac0-o_O-ellipsized_1iurgbx
房间类型、床数量和房客数量,地址为:span.detailWithoutWrap_j1kt73
4.4.2 项目实践
用Selenium获取Airbnb第一页的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
import time
caps = webdriver.DesiredCapabilities().FIREFOX
caps["marionette"] = True
binary = FirefoxBinary(r'C:\Program Files\Firefox Developer Edition\firefox.exe')
# 把上述地址改成你电脑中Firefox程序的地址
# 如果没改,会出现selenium.common.exceptions.SessionNotCreatedException: Message: Unable to find a matching set of capabilities
#用 selenium 的 driver 来启动 firefox
driver = webdriver.Firefox(firefox_binary=binary, capabilities=caps)
#在虚拟浏览器中打开 Airbnb 页面。使用Selenium打开该页面
driver.get("https://zh.airbnb.com/s/Shenzhen--China?page=1")
time.sleep(20)
#找到页面中所有的出租房。用Selenium的css selector获取所有房屋的div数据
rent_list = driver.find_elements_by_css_selector('div._1788tsr0')
#对于每一个出租房
for eachhouse in rent_list:
#找到评论数量
try:
comment = eachhouse.find_element_by_css_selector('span._gb7fydm')
comment = comment.text
except:
comment = 0
#找到价格
price = eachhouse.find_element_by_css_selector('span._hylizj6')
price = price.text[4:]
#找到名称
name = eachhouse.find_element_by_css_selector('div._ew0cqip')
name = name.text
#找到房屋类型,大小
details = eachhouse.find_elements_by_css_selector('div._saba1yg small div span')
details = details[0].text
house_type = details.split(" · ")[0]
bed_number = details.split(" · ")[1]
print (comment, price, name, house_type, bed_number)

进阶:将Selenium的控制CSS加载、控制图片加载和控制JavaScript加载加入本实践项目的代码中,从而提升爬虫的速度。
https://github.com/Santostang/PythonScraping/blob/master/%E7%AC%AC%E4%B8%80%E7%89%88/Cha%204%20-%E5%8A%A8%E6%80%81%E7%BD%91%E9%A1%B5%E6%8A%93%E5%8F%96/Cha%204%20_%E7%AB%A0%E6%9C%AB%E5%AE%9E%E6%88%98.ipynb

11. 相关参考

11.1. allitebooks

Web Scraping with Python(有2版)
Website Scraping with Python -
Learning Scrapy
Webbots, Spiders, and Screen Scrapers
Getting Started with Beautiful Soup

11.2. 其他

Web Scraping with Python Collecting More Data from the Modern Web- 城通网盘 ||似乎与Ryan Mitchell的是同一本
Learning Selenium Testing Tools with Python
Python Requests Essentials
Web Scraping with Python, 2nd Edition
Practical Web Scraping for Data Science
Python Web Scraping Cookbook - 2018
Spider Webb’s Angels
Python Web Scraping
Python数据抓取技术与实战 仅京东

11.3. 中文书籍

  • Python网络爬虫从入门到实践,唐松
  1. Python爬虫入门一之综述
  2. Python爬虫入门二之爬虫基础了解
  3. Python爬虫入门三之Urllib库的基本使用
  4. Python爬虫入门四之Urllib库的高级用法
  5. Python爬虫入门五之URLError异常处理
  6. Python爬虫入门六之Cookie的使用
  7. Python爬虫入门七之正则表达式

    11.8.2. 二、爬虫实战

  8. Python爬虫实战一之爬取糗事百科段子
  9. Python爬虫实战二之爬取百度贴吧帖子
  10. Python爬虫实战三之实现山东大学无线网络掉线自动重连
  11. Python爬虫实战四之抓取淘宝MM照片
  12. Python爬虫实战五之模拟登录淘宝并获取所有订单
  13. Python爬虫实战六之抓取爱问知识人问题并保存至数据库
  14. Python爬虫实战七之计算大学本学期绩点
  15. Python爬虫实战八之利用Selenium抓取淘宝匿名旺旺

    11.8.3. 三、爬虫利器

  16. Python爬虫利器一之Requests库的用法
  17. Python爬虫利器二之Beautiful Soup的用法
  18. Python爬虫利器三之Xpath语法与lxml库的用法
  19. Python爬虫利器四之PhantomJS的用法
  20. Python爬虫利器五之Selenium的用法
  21. Python爬虫利器六之PyQuery的用法

    11.8.4. 四、爬虫进阶

  22. Python爬虫进阶一之爬虫框架概述
  23. Python爬虫进阶二之PySpider框架安装配置
  24. Python爬虫进阶三之爬虫框架Scrapy安装配置
  25. Python爬虫进阶四之PySpider的用法
  26. Python爬虫进阶五之多线程的用法
  27. Python爬虫进阶六之多进程的用法
  28. Python爬虫进阶七之设置ADSL拨号服务器代理

    12. 附录

    必备软件的安装与故障排除

    12.1. 平台

    搭建平台、开发环境
    Linux、Windows、Mac

    12.2. 软件安装及环境配置

    Anaconda: https://www.continuum.io/downloads
    Jupyter
    默认端口:8888
    为什么推荐大家使用Jupyter学习和编写Python脚本呢?
    Jupyter:交互式编程和展示功能。
    分段执行,编写和测试时边看边写,加快调试速度。
    能够把运行和输出的结果保存下来,下次打开这个Notebook时也可以看到之前运行的结果。
    还可以添加各种元素,比如图片、视频、链接等,同时还支持Markdown,可以充当PPT使用。
    Alt + Enter jupyter快捷键
    MongoDB环境配置
    Robomongo:MongoDB数据库的可视化管理工具。
    MySQL环境配置
    Python、Python多版本共存配置
    PyCharm
    Redis、修改Redis配置
    Redis Desktop Manager:Redis的可视化管理工具。

13. 术语表

Anaconda:Python开发集成环境。南美洲的巨蟒。自带Python、pip和Jupyter。
第三方库:可理解为供用户调用的代码组合。在安装某个库之后,可以直接调用其中的功能,使得我们不用一个代码一个代码地实现某个功能。
代码缩进:代码要按照结构以Tab键或者4个空格进行缩进严格缩进
DT(Data Technology,数据技术)
命令提示符。输入一些命令后,可执行对系统的管理。 Windows的cmd,开始按钮→cmd。Mac的terminal。应用程序→terminal。
爬虫:
pip:Python安装各种第三方库(package)的工具。
Python:蟒蛇
数据交换:网站与用户的沟通本质。
print
Python不需要在使用之前声明需要使用的变量和类别。
字符串(string):单引号(’)或双引号(”)
连接字符串: +
数字(Number):数字用来存储数值
整数(int)
浮点数(float):由整数和小数部分组成。
列表(list):能够包含任意种类的数据类型和任意数量。
创建列表非常容易,只要把不同的变量放入方括号中,并用逗号分隔即可,例如list0 = [“a”,2,”c”,4]
增删查改、索引、切片
字典(Dictionaries):一种可变容器模型。
键(key)和值(value)。key必须唯一,但是值不用。值也可以取任何数据类型。
遍历
条件语句:满足条件的时候才执行某部分代码。条件为布尔值,也就是只有True和False两个值。
当if判断条件成立时才执行后面的语句;当条件不成立的时候,执行else后面的语句
如果需要判断的有多种条件,就需要用到elif
无序:字典
有序:列表、元组
对象有两种,即可更改(mutable)与不可更改(immutable)对象。在Python中,strings、tuples和numbers是不可更改对象,而list、dict等是可更改对象。
循环语句:多次执行一个代码片段。
循环分为for循环和while循环。
for循环:在一个给定的顺序下重复执行。
while循环:不断重复执行,只要能满足一定条件。
函数
代码庞大复杂时,使得代码易读,可重复使用,并且容易调整顺序。
函数的参数与返回值
面向过程编程:根据业务逻辑从上到下写代码,最容易被初学者接受。
函数式编程:把某些功能封装到函数中,需要用时可以直接调用,不用重复撰写。函数式的编程方法节省了大量时间。只需要写清楚输入和输出变量并执行函数即可。
面向对象编程:把函数进行分类和封装后放入对象中,使得开发更快、更强。首先要创建封装对象,然后还要通过对象调用被封装的内容。在某些应用场景下,面向对象编程能够显示出更大的优势。
如果各个函数之间独立且无共用的数据,就选用函数式编程;如果各个函数之间有一定的关联性,选用面向对象编程比较好。
特性与行为,属性和方法
面向对象的两大特性:封装和继承。
封装:把内容封装好,再调用封装好的内容。使用构造方法将内容封装到对象中,然后通过对象直接或self间接获取被封装的内容。
继承:以普通的类为基础建立专门的类对象。子继承了父的某些特性。将多个类共有的方法提取到父类中,子类继承父类中的方法即可,不必一一实现每个方法。
【状态码】
200,请求成功
4xx,客户端错误
5xx,服务器错误
【请求头】
Headers:提供了关于请求、响应或其他发送实体的信息。
如果没有指定请求头或请求的请求头和实际网页不一致,就可能无法返回正确的结果。
Chrome浏览器的检查。单击需要请求的网页,在Headers中可以看到Requests Headers的详细信息。
请求头的信息为:
GET / HTTP/1.1
Host: www.santostang.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36
Accept:
text/html, application/xhtml+xml, application/xml; q=0.9, image/webp, /; q=0.8 Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US, en; q=0.8, zh-CN; q=0.6, zh; q=0.4, zh-TW; q=0.2
GET请求,密码会显示在URL中,非常不安全。
POST请求,
【动态网页】
AJAX(Asynchronous Javascript And XML,异步JavaScript和XML),一种异步更新技术。
单击“更多”,url地址没有任何改变,有新内容加载出来。
数据不会出现在网页源代码中。但是有JavaScript代码。
最后呈现出来的数据是通过JavaScript加载的。
通过在后台与服务器进行少量数据交换就可以使网页实现异步更新。
在不重新加载整个网页的情况下对网页的某部分进行更新。
减少了网页重复内容的下载
节省了流量
更小、更快、更友好
传统的网页必须重载整个网页页面
动态网页的例子
http://www.santostang.com/2018/07/04/hello-world/
页面下面的评论用JavaScript加载。评论数据没法在在网页源代码找到。
注释:#

https://getman.cn/ 在线测试

  • 首先看有没有移动端版本
  • 按网页展开比按ID循环爬取要好,某些网站会设定特定的网页,当这些网页被访问时会让设备处于一定时间的封禁状态,展开式爬去绕过这种反爬陷阱可能性相对较高

爬虫主要是和[[网页]]打交道。

网络协议 爬取原理 爬取任何一个网页的方法与思路

与爬虫相关的Web前端:[[HTML]]结构、[[CSS]]样式、[[JavaScript]]功能、[[Xpath]]和[[JSON]]。

辅助工具:[[chardet]] [[requests]] [[Firebug]] [[lxml]] [[BeautifulSoup4]] [[mechanize]] [[urllib]] [[Scrapy]] [[PhantomJS]]

爬虫是快速获取数据最重要的方式,相比其它语言,Python爬虫更简单、高效

https://docs.python.org/3/library/html.parser.html

== 累积 ==

  • json格式如果信息显示不全,可自己拼接API(&和json正文是最佳提示)
  • 哪些页面出现多少问题
  • 每分钟爬多少

==案例==

基础知识及案例。

1. 库的说明

1.1. re

Python正则表达式文档:https://docs.python.org/3/library/re.html
Python正则表达式的3种方法,分别是match、search和findall。

re.match

re.match:从字符串起始位置匹配,有则返回re.Match object,没有则返回none。

re.match(pattern, string, flags=0)

  • pattern:正则表达式,包含一些特殊的字符
  • string:被匹配的原字符串
  • flags:控制正则表达式的匹配方式,如是否区分大小写、多行匹配等。

字符串匹配:

1
2
3
4
5
6
7
8
9
10
11
12
import re
m = re.match('www', 'www.santostang.com')
print ("匹配的结果: ", m)
print ("匹配的起始与终点: ", m.span())
print ("匹配的起始位置: ", m.start())
print ("匹配的终点位置: ", m.end())

# 得到的结果为:
# 匹配的结果: <re.Match object; span=(0, 3), match='www'>
# 匹配的起始与终点: (0, 3)
# 匹配的起始位置: 0
# 匹配的终点位置: 3

正则匹配:

1
2
3
4
5
6
7
8
9
10
11
line = "Fat cats are smarter than dogs, is it right? "
m = re.match( r'(.*) are (.*? ) dogs', line)
print ('匹配的整句话', m.group(0))
print ('匹配的第一个结果', m.group(1))
print ('匹配的第二个结果', m.group(2))
print ('匹配的结果列表', m.groups())
# 得到的结果为:
# 匹配的整句话Fat cats are smarter than dogs
# 匹配的第一个结果Fat cats
# 匹配的第二个结果smarter than
# 匹配的结果列表 ('Fat cats', 'smarter than')

https://docs.python.org/3/library/re.html#match-objects

  • re.match只能从字符串的【起始】位置进行匹配。
  • re.search扫描整个字符串并返回【第一个】成功的匹配。
  • 其他方面re.search与re.match一样。
    1
    2
    3
    4
    5
    6
    7
    8
    import re
    m_match = re.match('com', 'www.santostang.com')
    m_search = re.search('com', 'www.santostang.com')
    print (m_match)
    print (m_search)
    # 得到结果为:
    # None
    # <re.Match object; span=(15, 18), match='com'>

re.findall方法

  • match和search,只能找到一个匹配所写的模式
  • findall可以找到所有的匹配,返回列表
    1
    2
    3
    4
    5
    6
    7
    import re
    m_match = re.match('[0-9]+', '12345 is the first number, 23456 is the sencond')
    m_search = re.search('[0-9]+', 'The first number is 12345, 23456 is the sencond')
    m_findall = re.findall('[0-9]+', '12345 is the first number, 23456 is the sencond')
    print (m_match.group())
    print (m_search.group())
    print (m_findall)

上述代码的’[0-9]+’表示任意长度的数字,然后在后面的字符串中进行匹配。

为什么要在match的模式前加上r

r:raw string,纯粹的字符串。使用它就不会对引S号里面的反斜杠\进行特殊处理。
在正则表达式中有一些类似\d(匹配任何数字)的模式,都要进行转译。
假如你需要匹配文本中的字符\,使用编程语言表示的正则表达式里就需要4个反斜杠\\\\

  • 前两个反斜杠\\和后两个反斜杠\\各自在编程语言里转义成一个反斜杠\
  • 所以4个反斜杠\\\\就转义成了两个反斜\\
  • 这两个反斜杠\\最终在正则表达式里转义成一个反斜杠\
    Python里的原生字符串很好地解决了这个问题,在正则表达式里不会再转义,这个例子中的正则表达式可以使用r\\表示。

(.) are会尽量匹配最多的字符。贪婪模式
(.
? )会尽量匹配尽量少的字符。非贪婪模式

1.2. bs4

使用BeautifulSoup解析网页
BeautifulSoup是一个工具箱。通过【解析文档】来提取数据。

  • 可以从HTML或XML文件中提取数据。
  • 可以提供一些简单的、Python式的函数用来处理导航、搜索、修改分析树等。
    简单,不需要多少代码就可以写出一个完整的应用程序。非常强大。
    支持Python标准库中的HTML解析器,还支持一些第三方的解析器。

BeautifulSoup 4主要特性、适合做什么、怎样使用
使用BeautifulSoup获取博客标题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
from bs4 import BeautifulSoup

link = "http://www.santostang.com/"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers= headers)

soup = BeautifulSoup(r.text,"html.parser") # 将网页响应体的字符串转化为soup对象

# <h1>元素,class为' post-title',提取<a>元素中的文字,strip()的功能是把字符串左右的空格去掉。find只是用来找到第一条结果。
first_title = soup.find("h1", class_="post-title").a.text.strip()

print ("第一篇文章的标题是:", first_title)

title_list = soup.find_all("h1", class_="post-title")
for i in range(len(title_list)):
title = title_list[i].a.text.strip()
print ('第 %s 篇文章的标题是:%s' %(i+1, title))

找所有结果,用find_all。find_all返回列表。

BeautifulSoup的其他功能
soup.prettify() 代码美化
首先,需要把:

1
soup = BeautifulSoup(html, "html.parser")

代码转化成BeautifulSoup对象。
BeautifulSoup对象是一个复杂的【树】形结构,它的每一个【节点】都是一个【Python对象】。

提取对象的3种方法:

遍历文档树
搜索文档树
CSS选择器

1.遍历文档树
先爬树干,然后小树干,最后树枝。

1
2
3
4
5
6
soup.header.h3:获取取<h3>标签。如结果为:<h3 id="name">大数据@唐松Santos</h3>)。
soup.header.div.contents:列出某个标签的所有子节点。只能获取第一代子标签。
soup.header.div.contents[1]:索引为1的子标签。
soup.header.div.children:获得所有子标签。只能获取第一代子标签。
soup.header.div.descendants:获得所有子子孙孙标签
soup.header.div.a.parent:获得父节点的内容:

遍历文档树的方法其实使用得比较少。

2.搜索文档树
最常用的是搜索文档树。
最常用的是find()和find_all()。
find()和find_all()方法还可以和re正则结合起来使用

1
2
3
4
5
for tag in soup.find_all(re.compile("^h")):  # 找出所有以h开头的标签,这表示<header>和<h3>的标签都会被找到  
print(tag.name)
# 输出的结果是:
# header
# h3

如果传入正则表达式作为参数,Beautiful Soup就会通过正则表达式的match()来匹配内容。

  1. CSS选择器
1
2
3
4
5
6
7
8
9
10
11
12
13
通过tag标签逐层查找:soup.select("header h3")⇒得到的结果是:[<h3 id="name">大数据@唐松Santos</h3>]
通过某个tag标签下的直接子标签遍历,:
soup.select("header > h3") ⇒[<h3 id="name">大数据@唐松Santos</h3>]
soup.select("div > a") ⇒ <div>下所有的< a>标签
[<a href="http://www.santostang.com/feed/" rel="nofollow" target="_blank"title="RSS"><i aria-hidden="true" class="fa fa-rss"></i></a>, <a href="http://weibo.com/santostang" rel="nofollow" target="_blank" title="Weibo"><i aria-hidden="true" class="fa fa-weibo"></i></a>, …]

soup.select('a[href^="http://www.santostang.com/"]'):找所有链接以http://www.santostang.com/开始的<a>标签
得到的结果是:
[<a href="http://www.santostang.com/feed/" rel="nofollow" target="_blank"title="RSS"><i aria-hidden="true" class="fa fa-rss"></i></a>,
<a href="http://www.santostang.com/">首页</a>,
<a href="http://www.santostang.com/about-me/">关于我</a>,
<a href="http://www.santostang.com/post-search/">文章搜索</a>,
<a href="http://www.santostang.com/wp-login.php">登录</a>]

5.3 使用lxml解析网页
一些比较流行的解析库
Xpath语法(如lxml),同样是效率比较高的解析方法。lxml使用C语言编写,解析速度比不使用lxml解析器的BeautifulSoup快一些。

5.3.2 使用lxml获取博客标题
使用lxml提取网页源代码数据的3种方法
XPath选择器
CSS选择器
BeautifulSoup的find()方法

和BeautifulSoup相比,lxml还多了一种XPath选择器方法。

XPath是一门在XML文档中查找信息的语言。
XPath使用路径表达式来选取XML文档中的节点或节点集,也可以用在HTML获取数据中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests
from lxml import etree

link = "http://www.santostang.com/"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers= headers)

html = etree.HTML(r.text) # 解析为lxml的格式
title_list = html.xpath('//h1[@class="post-title"]/a/text()') # 用XPath读取里面的内容
print (title_list)

//:无论在文档中什么位置
//h1:所有<h1>元素
//h1[@class="post-title"]:<h1>中class为"post-title"的元素
/a表示选取<h1>子元素的<a>元素
/text()表示提取<a>元素中的所有文本。

chrome审查,右键,选取元素,Copy→Copy XPath

5.3.3 XPath的选取方法
XPath使用路径表达式可以在网页源代码中选取节点,它是沿着路径来选取的,如表5-3所示。
XPath路径表达式及其描述 https://res.weread.qq.com/wrepub/epub_928559_47
下面是一个XML文档,我们将用XPath提取其中的一些数据。

1
2
3
4
5
6
7
8
9
<? xml version="1.0" encoding="ISO-8859-1"? >
<bookstore>
<book>
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>

XPath的一些路径表达式及其结果:https://res.weread.qq.com/wrepub/epub_928559_48

https://github.com/Santostang/PythonScraping/blob/master/%E7%AC%AC%E4%B8%80%E7%89%88/Cha%205%20-%E8%A7%A3%E6%9E%90%E7%BD%91%E9%A1%B5/Cha%205%20-%E8%A7%A3%E6%9E%90%E7%BD%91%E9%A1%B5.ipynb

5.5 BeautifulSoup爬虫实践:房屋价格数据
目的:获取安居客网站上北京二手房的数据。获取前10页二手房源的名称、价格、几房几厅、大小、建造年份、联系人、地址、标签。
网址:https://beijing.anjuke.com/sale/。
5.5.1 网站分析

5.5.2 项目实践
通过以上分析已经能够获得各个数据所在的地址,接下来用requests加上BeautifulSoup获取安居客北京二手房结果的第一页数据,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import requests
from bs4 import BeautifulSoup
import time

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36'}
for i in range(1,11):
link = 'https://beijing.anjuke.com/sale/p' + str(i)
r = requests.get(link, headers = headers)
print ('现在爬取的是第', i, '页')

soup = BeautifulSoup(r.text, 'lxml')
house_list = soup.find_all('li', class_="list-item")

for house in house_list:
name = house.find('div', class_ ='house-title').a.text.strip()
price = house.find('span', class_='price-det').text.strip()
price_area = house.find('span', class_='unit-price').text.strip()

no_room = house.find('div', class_='details-item').span.text
area = house.find('div', class_='details-item').contents[3].text
floor = house.find('div', class_='details-item').contents[5].text
year = house.find('div', class_='details-item').contents[7].text
broker = house.find('span', class_='brokername').text
broker = broker[1:]
address = house.find('span', class_='comm-address').text.strip()
address = address.replace('\xa0\xa0\n ',' ')
tag_list = house.find_all('span', class_='item-tags')
tags = [i.text for i in tag_list]
print (name, price, price_area, no_room, area, floor, year, broker, address, tags)
time.sleep(5)
```
进阶:获取其中的各项数据,如小区名称、房屋类型、房屋朝向、参考首付等。

https://github.com/Santostang/PythonScraping/blob/master/%E7%AC%AC%E4%B8%80%E7%89%88/Cha%205%20-%E8%A7%A3%E6%9E%90%E7%BD%91%E9%A1%B5/Cha%205%20_%E7%AB%A0%E6%9C%AB%E5%AE%9E%E6%88%98.ipynb
### 1.2.1. requests
```py
import requests
r = requests.get('http://www.santostang.com/')
# ========【r的方法】========
# r response响应对象,存储了服务器响应的内容,以从中获取需要的信息
# r.encoding 服务器内容使用的文本编码。
# r.status_code 响应状态码。检测请求是否正确响应。
# r.text 字符串方式的响应体。会自动根据响应头部的字符编码进行解码。
# r.content 字节方式的响应体。会自动解码gzip和deflate编码的响应数据。gzip文件用这个。
# r.json() Requests中内置的JSON解码器。
# r.url r对应的请求的页面网址
# ========【requests.get的参数设置】========
## URL参数、请求头、发送POST请求、设置超时

## ----------【params】:dict ----------
### get传递url参数。http://httpbin.org/get?key1=value1&key2=value2
key_dict = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=key_dict)
## ----------【headers】:dict ----------
### 有的网站不带请求头会返回错误的数据。带请求头使程序更像人的手动行为
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36',
'Host': 'www.santostang.com'
}
r = requests.get('http://www.santostang.com/', headers=headers)
## ----------【data】: dict ----------
### 用于提交表单。data在发出请求的时候会自动编码为表单形式。
key_dict = {'key1': 'value1', 'key2': 'value2'}
r = requests.post('http://httpbin.org/post', data=key_dict)
## ----------【timeout】: 单位为秒 ----------
### 如果服务器在timeout秒内没有应答,就返回异常。一般会把这个值设置为20秒。
link = "http://www.santostang.com/"
r = requests.get(link, timeout= 0.001)
## 返回的异常为:

## ConnectTimeout: HTTPConnectionPool(host='www.santostang.com', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.HTTPConnection object at 0x00000000077806D8>, 'Connection to www.santostang.com timed out. (connect timeout=0.001)'))

## 异常值的意思是,时间限制在0.001秒内,连接到地址为www.santostang.com的时间已到。

# https://github.com/Santostang/PythonScraping/blob/master/第一版/Cha 3 -静态网页抓取/Cha 3 -静态网页抓取.ipynb
```
### 1.2.2. Selenium
Selenium选择元素的方法有很多。
xpath和css_selector是比较好的方法,一方面比较清晰,另一方面相对其他方法定位元素比较准确。
```xpath
查找单个元素:
find_element_by_class_name:class选择
如<p class="content">Site content goes here.</p>⇒driver.find_element_by_class_name('content')。
find_element_by_css_selector:class选择
如<div class='bdy-inner'>test</div>⇒driver.find_element_by_css_selector ('div.bdy-inner')。
find_element_by_id:id选择
如<div id='bdy-inner'>test</div>⇒driver.find_element_by_id('bdy-inner')。
find_element_by_link_text:链接地址选择
如<a href="continue.html">Continue</a>⇒driver.find_element_by_link_text('Continue')。
find_element_by_name:name选择
如<input name="username"type="text" />⇒driver.find_element_by_name('username')。
find_element_by_partial_link_text:链接的部分地址选择
如 <a href="continue.html">Continue</a>⇒driver.find_element_by_partial_link_text('Conti')。
find_element_by_tag_name:名称选择
如<h1>Welcome</h1>⇒driver.find_element_by_tag_name('h1')。
find_element_by_xpath:通过xpath选择
如<form id="loginForm"> ⇒driver.find_element_by_xpath("//form[@id='loginForm']")。

查找多个元素时,[element]后加上s:
find_elements_by_class_name
find_elements_by_css_selector
find_elements_by_link_text
find_elements_by_name
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_xpath


除了Selenium的click操作元素方法,常见的操作元素方法:
● Clear清除元素的内容。
● send_keys模拟按键输入。
● Click单击元素。
● Submit提交表单。

comment = driver.find_element_by_css_selector(‘div.bdy-inner’)
content = comment.find_element_by_tag_name(‘p’)

Selenium的高级操作:

1
2
3
4
5
6
7
fp = webdriver.FirefoxProfile()
# 1. 限制CSS的页面
fp.set_preference("permissions.default.stylesheet",2)
# 2. 限制图片的显示。极大地提高网络爬虫的效率。图片文件相对于文字、CSS、JavaScript等文件都比较大,加载需要较长时间。
fp.set_preference("permissions.default.image",2)
# 3. 控制JavaScript的运行。大多数网页都会利用JavaScript异步加载很多内容,如果这些内容不是需要的,其加载会浪费时间。
fp.set_preference("javascript.enabled", False)

全部限制对于加载速度的提升效果最好。如果能够限制,那么最好限制多种加载,这样的效果最好。
具体的加载速度提升还得看相应的网页,若网页的图片比较多,则限制图片的加载肯定效果很好。

参考链接:selenium

2. 典型应用

2.0.3. 简单的爬虫

【用到的库】requests + bs4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# https://github.com/Santostang/PythonScraping/blob/master/第一版/Cha 2 - 编写你的第一个网络爬虫/Cha 2 _章末实战.ipynb  
#!/usr/bin/python
# coding: utf-8

import requests

from bs4 import BeautifulSoup #从bs4这个库中导入BeautifulSoup
# 第一步:获取页面
link = "http://www.santostang.com/"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers= headers) # requests的headers伪装成浏览器访问。r是requests的Response回复对象。
# 第二步:提取需要的数据
soup = BeautifulSoup(r.text, "html.parser") # 使用BeautifulSoup解析这段网页。把HTML代码转化为soup对象。r.text是获取的网页内容代码
title = soup.find("h1", class_="post-title").a.text.strip() # 提取第一篇文章的标题
print (title)
# 第三步:存储数据
with open('title_test.txt', "a+") as f:
f.write(title)

```
### 2.0.4. 爬取豆瓣电影TOP250
【用到的库】requests + bs4
获取豆瓣电影TOP250的所有电影的名称
网页地址为:https://movie.douban.com/top250
第一页有25个电影
获取所有的250页电影
总共10页的内容
第二页:https://movie.douban.com/top250? start=25
第三页:https://movie.douban.com/top250? start=50


```py
import requests
from bs4 import BeautifulSoup

def get_movies():
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36',
'Host': 'movie.douban.com'
}
movie_list = []
for i in range(0,10):
link = 'https://movie.douban.com/top250?start=' + str(i * 25)
r = requests.get(link, headers=headers, timeout= 10)
print (str(i+1),"页响应状态码:", r.status_code)

soup = BeautifulSoup(r.text, "lxml")
div_list = soup.find_all('div', class_='hd')
for each in div_list:
movie = each.a.span.text.strip()
movie_list.append(movie)
return movie_list

movies = get_movies()
print (movies)
# 原文有误
# 用 ]: 便于在 ipynb 中查找下一项
```
参考链接:豆瓣电影(https://github.com/Santostang/PythonScraping/blob/master/第一版/Cha 3 -静态网页抓取/Cha 3 _章末实战.ipy)

进阶问题:获取TOP 250电影的英文名、港台名、导演、主演、上映年份、电影分类以及评分。
### 2.0.5. 爬取动态网页
【用到的库】requests + json
AJAX加载的动态网页,有两种爬取方法:
1)通过浏览器审查元素解析地址。
2)通过Selenium模拟浏览器抓取。

两个特别重要的变量,即offset和limit。
limit:每一页评论数量的最大值
offset:本页的第一条评论是总的第几条

```py
import requests
import json

def single_page_comment(link):
headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers= headers)
# 获取 json 的 string
json_string = r.text
json_string = json_string[json_string.find('{'):-2]
json_data = json.loads(json_string) # 使用json.loads()把字符串格式的响应体数据转化为json数据
comment_list = json_data['results']['parents'] # json数据的结构提取

for eachone in comment_list:
message = eachone['content']
print (message)

for page in range(1,4):
link1 = "https://api-zero.livere.com/v1/comments/list?callback=jQuery112407875296433383039_1506267778283&limit=10&offset="
link2 = "&repSeq=3871836&requestPath=%2Fv1%2Fcomments%2Flist&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&_=1506267778285"
page_str = str(page)
link = link1 + page_str + link2
print (link)
single_page_comment(link)
```
参考链接:
https://github.com/Santostang/PythonScraping/blob/master/第一版/Cha 4 -动态网页抓取/Cha 4 -动态网页抓取.ipynb
### 2.0.6. 通过Selenium模拟浏览器抓取
```py
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("https://www.dianping.com/search/category/7/10/p1")

# 如果运行之后,发现程序报错:
# selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.
# 可以到https://github.com/mozilla/geckodriver/releases下载最新版的geckodriver,解压后可以放在Python安装目录(可能是Script子文件夹)下(可能需并放在环境变量的PATH中)。
from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
caps = webdriver.DesiredCapabilities().FIREFOX
caps["marionette"] = False

path = r'D:\\Program Files\\Mozilla Firefox\\firefox.exe'
binary = FirefoxBinary(path) # Firefox程序的地址
driver = webdriver.Firefox(firefox_binary=binary, capabilities=caps)
driver.get("http://www.santostang.com/2017/03/02/hello-world/")

import time
try:
load_more = driver.find_element_by_css_selector('div.tie-load-more') # 更多或下一页
load_more.click() # 模拟单击
except:
pass
comments = driver.find_elements_by_css_selector('div.bdy- inner')
time.sleep(5)

user = driver.find_element_by_name("username") #找到用户名输入框
user.clear #清除用户名输入框内容
user.send_keys("1234567") #在框中输入用户名
pwd = driver.find_element_by_name("password") #找到密码输入框
pwd.clear #清除密码输入框内容
pwd.send_keys("******") #在框中输入密码
driver.find_element_by_id("loginBtn").click() #单击登录

2.0.7. 深圳短租

目的:获取Airbnb深圳前20页的短租房源的名称、价格、评价数量、房屋类型、床数量和房客数量。监控和了解竞争对手的房屋名称和价格,让自己的房子有竞争力。
网址:https://zh.airbnb.com/s/Shenzhen--China?page=1

4.4.1 网站分析

一个房子的所有数据。地址为:div.infoContainer_v72lrv。
价格数据,地址为:div.priceContainer_4ml1ll
评价数据,地址为:span.text_5mbkop-o_O-size_micro_16wifzf-o_O-inline_g86r3e
房屋名称数据,地址为:div.listingNameContainer_kq7ac0-o_O-ellipsized_1iurgbx
房间类型、床数量和房客数量,地址为:span.detailWithoutWrap_j1kt73

4.4.2 项目实践
用Selenium获取Airbnb第一页的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
import time

caps = webdriver.DesiredCapabilities().FIREFOX
caps["marionette"] = True
binary = FirefoxBinary(r'C:\Program Files\Firefox Developer Edition\firefox.exe')
# 把上述地址改成你电脑中Firefox程序的地址
# 如果没改,会出现selenium.common.exceptions.SessionNotCreatedException: Message: Unable to find a matching set of capabilities

#用 selenium 的 driver 来启动 firefox
driver = webdriver.Firefox(firefox_binary=binary, capabilities=caps)
#在虚拟浏览器中打开 Airbnb 页面。使用Selenium打开该页面
driver.get("https://zh.airbnb.com/s/Shenzhen--China?page=1")

time.sleep(20)
#找到页面中所有的出租房。用Selenium的css selector获取所有房屋的div数据
rent_list = driver.find_elements_by_css_selector('div._1788tsr0')

#对于每一个出租房
for eachhouse in rent_list:
#找到评论数量
try:
comment = eachhouse.find_element_by_css_selector('span._gb7fydm')
comment = comment.text
except:
comment = 0

#找到价格
price = eachhouse.find_element_by_css_selector('span._hylizj6')
price = price.text[4:]

#找到名称
name = eachhouse.find_element_by_css_selector('div._ew0cqip')
name = name.text

#找到房屋类型,大小
details = eachhouse.find_elements_by_css_selector('div._saba1yg small div span')
details = details[0].text
house_type = details.split(" · ")[0]
bed_number = details.split(" · ")[1]
print (comment, price, name, house_type, bed_number)

进阶:将Selenium的控制CSS加载、控制图片加载和控制JavaScript加载加入本实践项目的代码中,从而提升爬虫的速度。

https://github.com/Santostang/PythonScraping/blob/master/%E7%AC%AC%E4%B8%80%E7%89%88/Cha%204%20-%E5%8A%A8%E6%80%81%E7%BD%91%E9%A1%B5%E6%8A%93%E5%8F%96/Cha%204%20_%E7%AB%A0%E6%9C%AB%E5%AE%9E%E6%88%98.ipynb

3. 工具及资源列表

3.1. 网络下载

Anaconda: https://www.continuum.io/downloads
Robomongo:MongoDB数据库的可视化管理工具。
Redis Desktop Manager:Redis的可视化管理工具。

Alt + Enter jupyter快捷键

3.2. 书籍辅助

  • Python网络爬虫从入门到实践,唐松
  • Github:https://github.com/Santostang/PythonScraping
    百度网:http://pan.baidu.com/s/1c2w9rck
    书本对应的Python网络爬虫的教学:www.santostang.com
    网站不会更改设计和框架,本书的网络爬虫代码可以一直使用
    作者自己的博客网站,可以避免一些法律上的风险

    3.3. 端口

    jupyter:8888

    4. 库

    4.1. Python第三方库

    基本格式:(安装时,把name替换为要安装的第三方库)
  • pip install name
  • pip install -i https://pypi.tuna.tsinghua.edu.cn/simple name
  • 科学计算的包,如Numpy、Scipy、Pandas和Matplotlib。
  • 机器学习、生物医学和天体物理学计算,如Scikit-Learn、BioPython。
  • 获取网页:requests、urllib、selenium
  • 解析数据:lxml、bs4的BeautifulSoup、re(标准库)
  • 存储数据:MySQL、MongoDB

    5. 附录

    6. 单项分析

    6.1. 是什么

    Anaconda:Python开发集成环境。南美洲的巨蟒。自带Python、pip和Jupyter。
    第三方库:可理解为供用户调用的代码组合。在安装某个库之后,可以直接调用其中的功能,使得我们不用一个代码一个代码地实现某个功能。
    DT(Data Technology,数据技术)

命令提示符。输入一些命令后,可执行对系统的管理。 Windows的cmd,开始按钮→cmd。Mac的terminal。应用程序→terminal。
爬虫:
pip:Python安装各种第三方库(package)的工具。
Python:蟒蛇
数据交换:网站与用户的沟通本质。

print
代码缩进:代码要按照结构以Tab键或者4个空格进行缩进严格缩进
注释:#

Python不需要在使用之前声明需要使用的变量和类别。
字符串(string):单引号(’)或双引号(”)
连接字符串: +

数字(Number):数字用来存储数值
整数(int)
浮点数(float):由整数和小数部分组成。

列表(list):能够包含任意种类的数据类型和任意数量。
创建列表非常容易,只要把不同的变量放入方括号中,并用逗号分隔即可,例如list0 = [“a”,2,”c”,4]
增删查改、索引、切片
字典(Dictionaries):一种可变容器模型。
键(key)和值(value)。key必须唯一,但是值不用。值也可以取任何数据类型。
遍历
条件语句:满足条件的时候才执行某部分代码。条件为布尔值,也就是只有True和False两个值。
当if判断条件成立时才执行后面的语句;当条件不成立的时候,执行else后面的语句
如果需要判断的有多种条件,就需要用到elif
无序:字典
有序:列表、元组
对象有两种,即可更改(mutable)与不可更改(immutable)对象。在Python中,strings、tuples和numbers是不可更改对象,而list、dict等是可更改对象。

循环语句:多次执行一个代码片段。
循环分为for循环和while循环。
for循环:在一个给定的顺序下重复执行。
while循环:不断重复执行,只要能满足一定条件。

函数
代码庞大复杂时,使得代码易读,可重复使用,并且容易调整顺序。
函数的参数与返回值

面向过程编程:根据业务逻辑从上到下写代码,最容易被初学者接受。
函数式编程:把某些功能封装到函数中,需要用时可以直接调用,不用重复撰写。函数式的编程方法节省了大量时间。只需要写清楚输入和输出变量并执行函数即可。
面向对象编程:把函数进行分类和封装后放入对象中,使得开发更快、更强。首先要创建封装对象,然后还要通过对象调用被封装的内容。在某些应用场景下,面向对象编程能够显示出更大的优势。
如果各个函数之间独立且无共用的数据,就选用函数式编程;如果各个函数之间有一定的关联性,选用面向对象编程比较好。
特性与行为,属性和方法
面向对象的两大特性:封装和继承。
封装:把内容封装好,再调用封装好的内容。使用构造方法将内容封装到对象中,然后通过对象直接或self间接获取被封装的内容。
继承:以普通的类为基础建立专门的类对象。子继承了父的某些特性。将多个类共有的方法提取到父类中,子类继承父类中的方法即可,不必一一实现每个方法。

【状态码】
200,请求成功
4xx,客户端错误
5xx,服务器错误
【请求头】
Headers:提供了关于请求、响应或其他发送实体的信息。
如果没有指定请求头或请求的请求头和实际网页不一致,就可能无法返回正确的结果。

Chrome浏览器的检查。单击需要请求的网页,在Headers中可以看到Requests Headers的详细信息。

请求头的信息为:
GET / HTTP/1.1
Host: www.santostang.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36
Accept:
text/html, application/xhtml+xml, application/xml; q=0.9, image/webp, /; q=0.8 Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US, en; q=0.8, zh-CN; q=0.6, zh; q=0.4, zh-TW; q=0.2

GET请求,密码会显示在URL中,非常不安全。
POST请求,
【动态网页】
AJAX(Asynchronous Javascript And XML,异步JavaScript和XML),一种异步更新技术。
单击“更多”,url地址没有任何改变,有新内容加载出来。
数据不会出现在网页源代码中。但是有JavaScript代码。
最后呈现出来的数据是通过JavaScript加载的。

通过在后台与服务器进行少量数据交换就可以使网页实现异步更新。
在不重新加载整个网页的情况下对网页的某部分进行更新。
减少了网页重复内容的下载
节省了流量
更小、更快、更友好

传统的网页必须重载整个网页页面

动态网页的例子
http://www.santostang.com/2018/07/04/hello-world/

页面下面的评论用JavaScript加载。评论数据没法在在网页源代码找到。

6.1.1. Selenium

Selenium官方文档:http://selenium-python.readthedocs.io/index.html。

Selenium要在整个网页加载出来后才开始爬取内容,速度往往较慢。

Selenium可以实现的功能:
操作元素对浏览器中的网页进行各种操作,包括登录。
模拟鼠标单击、双击、拖拽
获得网页中各个元素的大小
模拟键盘
浏览器渲染引擎。直接用浏览器在显示网页时解析HTML、应用CSS样式并执行JavaScript的语句。Selenium使用浏览器渲染,数据已经渲染到了HTML代码中。用chrome定位标签即可。
用脚本控制浏览器操作。Python的Selenium库模拟浏览器完成抓取。
Selenium:用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,浏览器自动按照脚本代码做出单击、输入、打开、验证等操作,就像真正的用户在操作一样。

用Selenium控制浏览器加载的内容,可加快Selenium的爬取速度。此类常用的方法有:
(1)控制CSS的加载。
(2)控制图片文件的显示。
(3)控制JavaScript的运行。
(1)控制CSS。因为抓取过程中仅仅抓取页面的内容,CSS样式文件是用来控制页面的外观和元素放置位置的,对内容并没有影响,所以我们可以限制网页加载CSS,从而减少抓取时间。

支持多个浏览器的调用:IE(7、8、9、10、11)、Firefox、Safari、Google Chrome、Opera等。最常用的是Firefox。

6.1.2. 正则表达式

元字符:https://res.weread.qq.com/wrepub/epub_928559_43 问加合星
https://regex101.com/
正则表达式:字符串操作的逻辑公式。用事先定义好的特定字符组合成规则字符串,用该规则字符串来过滤字符串。
正则表达式可以迅速地用极简单的方式达到字符串的复杂控制。

6.2. 为什么

为什么、好处、重要性、作用、意义、优势、不足、历史、现状、趋势、大背景。

6.2.1. 大数据及爬虫

技术创新驱动变革的潮流。
数据量爆发式增长的互联网时代。
大数据分析的火热。
大数据成为业界与学术界最火热的话题之一。
数据已经成为每个公司极为重要的资产。
互联网大量的公开数据为个人和公司提供了以往想象不到的可以获取的数据量。
网络爬虫技术是大数据分析的第一环。有助于获取有用的公开数据集。
理解了信息的获取、存储和整理,才有可能系统地收集和应用不同源头和千变万化的网站信息。
DT的核心是从信息的源头去理解和分析,以做出能打动对方的行动决策方案。
由谷歌搜索到现在的大数据时代,爬虫技术的重要性和广泛性一直很突出。
爬取目标网站的资料、分析和建立应用。 获取数据自动、实时、及时、省时。
电商市场的重要性日益凸显。了解对手的产品特点、价格以及销量情况,及时跟进产品开发进度和营销策略,从而知己知彼,赢得竞争。过去,两个痛点——无法自动化和无法实时获取。产品研发部门会手动访问一个个电商产品页面,人工复制并粘贴到Excel表格中,制作竞品分析报告。但是这种重复性的手动工作不仅浪费宝贵的时间,一不留神复制少了一个数字还会导致数据错误;对手产品的销量则是由某一家咨询公司提供报告,每周一次,但是报告缺乏实时性,难以针对快速多变的市场及时调整价格和营销策略。
学会一项新的技术
第一方企业(也就是拥有这些数据的企业)做出更好的决策
第三方企业也可从中受益
数据共享
Python:热门的开源软件(这意味着有人源源不断地开发更新且更强大的包给你用)
Python:简单、简洁、易学、有效、可扩展性的计算机语言。 最受欢迎的程序语言之一。 强大而丰富的库。
C语言:底层,学习成本大。

6.2.2. Jupyter

为什么推荐大家使用Jupyter学习和编写Python脚本呢?
Jupyter:交互式编程和展示功能。
分段执行,编写和测试时边看边写,加快调试速度。
能够把运行和输出的结果保存下来,下次打开这个Notebook时也可以看到之前运行的结果。
还可以添加各种元素,比如图片、视频、链接等,同时还支持Markdown,可以充当PPT使用。

6.3. 如何

不断解决遇到的疑惑。
科技如何给大家带来实效
数据的存储对公司有什么影响
如何存储数据⇒高效利用 方便对接其他部门和业务
如何使用淘宝网上所有绿色产品(如空气净化器)的销量数据来做潜在市场评估
如何一直高效率、持续不断地从日新月异的网站中获取信息

6.3.1. 快捷

对初学者来说,使用BeautifulSoup从网页中提取需要的数据更加简单易用。

谷歌的有效信息检索速度比百度快
Stack Overflow上的回答可以比较快地解决问题
最新最好的回答很有可能是英文的

6.3.2. 获取动态网页的真实地址

Chrome浏览器的检查(审查元素)功能:浏览器右键⇒检查⇒Network⇒XHR或JS选项
Network:显示浏览器从网页服务器中得到的所有文件。一般这些数据以json文件格式获取。
在Network选项卡下,找到真正的评论文件。
单击Preview标签即可查看数据。可以按 ctrl+F 进行查找。顶部search也可以。
Elements会出现相应的code所在的地方。

6.4. 应用场景

6.4.1. 爬虫

一些附加值更高的“事”,如人工智能、统计建模等。
机器学习和统计算法分析
在营销领域可以帮助企业做好4P(Product:产品创新,Place:智能选址,Price:动态价格,Promotion:数据驱动的营销活动)
在金融领域,数据驱动的征信等应用会带来越来越大的价值。
公开数据的应用价值
所有网络数据
社交媒体的每一条发帖。社交媒体在用户生态圈的自我交互下产生大量文本、图片和视频数据。
团购网站的价格及点评。电商商产品的描述、价格
招聘网站的招聘信息
搜索引擎从数据库中提取搜索结果

6.5. 注意事项

爬虫有哪些潜在的法律纠纷、公司的爬虫合不合法 。
建立共利的互联网环境,不能把爬虫作为窃取数据的工具。
爬虫必须在合情、合法、合理的情况下获取和应用。
尊重数据供应者的知识产权和正常运作才能产生长久共利的环境。
保障对方平台的正常运作是每个程序员都应当做到的
法律:
互联网世界已经通过自身的协议建立起一定的道德规范(Robots协议)。该协议是国际互联网界通行的道德规范,虽然没有写入法律,但是每一个爬虫都应该遵守这项协议。
法律部分还在建立和完善中。
如果抓取的数据属于个人使用或科研范畴,基本不存在问题。当你爬取网站数据时,无论是否仅供个人使用,都应该遵守Robots协议。
而如果数据属于商业盈利范畴,就要就事而论,有可能属于违法行为,也有可能不违法。
大部分网站不欢迎使用程序进行登录,因为需要登录才能查看的数据不属于公开数据。最好不要使用此程序获取非公开数据或批量注册,若出现了问题,可能需负法律责任。

建议使用API。

Robots协议
Robots协议(爬虫协议)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。

https://www.taobao.com/robots.txt。
Allow开头的URL是允许robot访问的。例如,Allow:/article允许百度爬虫引擎访问/article.htm、/article/12345.com等。
Disallow不允许百度爬虫引擎访问的。例如,Disallow:/product/不允许百度爬虫引擎访问/product/12345.com等。
Disallow:/禁止百度爬虫访问除了Allow规定页面外的其他所有页面。

taobao的robots.txt对不同的搜索引擎所允许爬行范围不同。/product项对应淘宝内部的产品信息。当在搜索框中搜索“淘宝iphone7”的时候,Google可搜到淘宝中的产品,而百度不能。

过于快速或者频密的网络爬虫都会对服务器产生巨大的压力。→调集资源限制爬虫,保护用户的流量和减少有价值数据的流失。

反爬方维权:网站封锁你IP,法律行动。

将请求的速度限定在一个合理的范围之内。

每年的三月份会迎来一个爬虫高峰期。因为有大量的大学生五月份交论文,在写论文的时候会选择爬取数据,也就是3月份爬取数据,4月份分析数据,5月份交论文。

2007年,爱帮网利用垂直搜索技术获取了大众点评网上的商户简介和消费者点评,并且直接大量使用,大众点评网多次要求爱帮网停止使用这些内容,而爱帮网以自己是使用垂直搜索获得的数据为由,拒绝停止抓取大众点评网上的内容,并且质疑大众点评网对这些内容所享有的著作权。为此,双方开打了两场官司。2011年1月,北京海淀法院做出判决:爱帮网侵犯大众点评网著作权成立,应当停止侵权并赔偿大众点评网经济损失和诉讼必要支出。
2013年10月,百度诉360违反Robots协议。百度方面认为,360违反了Robots协议,擅自抓取、复制百度网站内容并生成快照向用户提供。2014年8月7日,北京市第一中级人民法院做出一审判决,法院认为被告奇虎360的行为违反了《反不正当竞争法》相关规定,应赔偿原告百度公司70万元。
虽然说大众点评上的点评数据、百度知道的问答由用户创建而非企业,但是搭建平台需要投入运营、技术和人力成本,所以平台拥有对数据的所有权、使用权和分发权。【网站的知识产权】
以上两起败诉告诉我们,在爬取网站的时候需要限制自己的爬虫,遵守Robots协议和约束网络爬虫程序的速度。如果违反了这些规定,很可能会吃官司,并且败诉的概率相当高。

7. 多项关系

7.1. 流程图

具体步骤及各步骤之间的关系。

7.1.1. 网络爬虫、数据采集

获【取】网页、解【析】网页(提取数据)、【存】储数据、整【理】。

  • 获取网页:给一个网址发送请求,该网址会返回整个网页的数据。类似于在浏览器中键入网址并按回车键,然后可以看到网站的整个页面。
  • 解析网页:从整个网页的数据中提取想要的数据。类似于在浏览器中看到网站的整个页面,但是你想找的是产品的价格,价格就是你想要的数据。
  • 存储数据:把数据存储下来。

三个流程的技术实现:

  • 获取网页
    获取网页的基础技术:request、urllib和selenium(模拟浏览器)。
    获取网页的进阶技术:多进程多线程抓取、登录抓取、突破IP封禁和服务器抓取。
  • 解析网页
    解析网页的基础技术:re正则表达式、BeautifulSoup和lxml。
    解析网页的进阶技术:解决中文乱码。
  • 存储数据
    存储数据的基础技术:存入txt文件和存入csv文件。
    存储数据的进阶技术:存入MySQL数据库和存入MongoDB数据库。

7.2. 分类树

7.3. 对比分析

主要的解析器及其优缺点
https://res.weread.qq.com/wrepub/epub_928559_44
https://res.weread.qq.com/wrepub/epub_928559_49
使用lxml的解析器将会解析得更快。

7.4. 关系图

互联网的运作和结构
爬虫程序是收集信息的基础。

==============================

8. 元学习(与物)

起始、终止、空格和换行,循环次数
是啥 为啥 逻辑清晰、循序渐进 查阅此书
动其心者,当具有大本大源
不断学习新技术,自我提高,实现目标和理想。不断更新和进步:互联网科技、网站信息也随之不断改变。
不能应用的技术称为魔术,只能用于表演。
学习的道路没有什么捷径可走,唯一的方法就是不断尝试、不断失败、不断改进。
通过实战解决实际问题。问题及解决方案实践
增强学习效果
富有逻辑的框架解构学习。将网络爬虫技术进行框架性的解构
认真阅读、手输代码,反复练习,熟能生巧。提升你的编程能力和编程效率
从实践中检验自己学习了多少知识
进一步巩固
进阶问题
答案并不是唯一解,对比思路

9. 个人提升(与人)

了解技术团队的运作模式
向香港中文大学市场营销学的研究生讲解Python网络爬虫技术,让这些商科学生掌握一些大数据时代重要的技术能力。
KYM框架
Know Your Company(了解你的公司)
Know Your Competitor(了解你的竞争对手)
Know Your Customer(了解你的客户)

10. 代码清单

10.1. 基础语法

10.1.1. py

int(number)
float(number)
for key,value in dict.items()
Python 100例 https://www.w3cschool.cn/python/python-100-examples.html

10.1.1.1. 类

class Person:   # 创建类          
    def _init_(self,name,age):  
        # _init_()方法称为类的构造方法。会自动执行。初始化以及规定传递的参数。self后面的参数列表。实例则传给self  
        # self 仅在类的定义中使用。表示对整个传递来的对象进行操作。  
        # 运行时类中self.会自动转为传进来obInstance.进行运算,即self = obInstance【自我理解】  

        self.name = name              
        self.age = age          
    def detail(self): #通过self调用被封装的内容              
        print (self.name)              
        print (self.age)      

obj1 = Person('santos',18)      
obj1.detail()  
# Python将obj1传给self参数,'santos'和18传给类的构造方法_init_中的name和age  

# 猫可以:喵喵叫、吃、喝、拉、撒  
# 狗可以:汪汪叫、吃、喝、拉、撒  

# 如果用继承的思想,就可以写成:  
# 动物:吃喝拉撒  
# 猫:喵喵叫(猫继承动物的功能)  
# 狗:汪汪叫(狗继承动物的功能)  

class Animal:  
    def eat(self):  
        print ("%s吃 " %self.name)  
    def drink(self):  
        print ("%s喝 " %self.name)  
    def shit(self):  
        print ("%s拉 " %self.name)  
    def pee(self):  
        print ("%s撒 " %self.name)  
class Cat(Animal):  
    def __init__(self,name):  
        self.name = name  
    def cry(self):  
        print ('喵喵叫')  
class Dog(Animal):  
    def __init__(self,name):  
        self.name = name  
    def cry(self):  
        print ('汪汪叫')  
c1 = Cat('小白家的小黑猫')  
c1.eat()  
c1.cry()  
d1 = Dog('胖子家的小瘦狗')  
d1.eat()  

# 小白家的小黑猫吃  
# 喵喵叫  
# 胖子家的小瘦狗吃  

10.1.2. 函数、类,可变与不可变

a = 1  
def fun(a):  
    a = 2  
fun(a)  
print (a)  
>>>1  

a为数字int,函数改变不了函数以外a的值。当一个引用传递给函数时,函数自动复制一份引用。函数里和函数外的引用是不一样的。  



a = []  
def fun(a):  
    a.append(1)  
fun(a)  
print (a)  
>>>[1]  
a为列表,函数将函数以外的a值改变了。函数内的引用指向的是可变对象列表a,函数内的列表a和函数外的列表a是同一个。  
class Person:  
    name="aaa"  

p1=Person()  
p2=Person()  
p1.name="bbb"  
print (p1.name)  
print (p2.name)  
print (Person.name)  

>>>bbb  
>>>aaa  
>>>aaa  
p1.name="bbb"表示实例调用了类变量,其实就是函数传参的问题。p1.name一开始指向类变量name="aaa",但是在实例的作用域里把类变量的引用改变了,就变成了一个实例变量,self.name不再引用Person的类变量name了。  
class Person:  
    name=[]  

p1=Person()  
p2=Person()  
p1.name.append(1)  
print (p1.name)  
print (p2.name)  
print (Person.name)  
>>>[1]  
>>>[1]  
>>>[1]  
!类中的可变量的慎重使用!!!!!!!!!!!!!!!ist、dict等是可更改对象,因此修改一个指向的对象时会把类变量也改变了。  

10.2. 基础算法

10.2.1. 循环打印输出从1到100的所有奇数

for i in range(1,101):  
    if i % 2 == 1:  
        print (i)  

10.2.2. 字符串批量替换

请将字符串“你好$$$我正在学Python@#@#现在需要&&&修改字符串”中的符号变成一个空格,需要输出的格式为:“你好 我正在学Python现在需要 修改字符串”。

# 方法1  
str1 = '你好$$$我正在学Python@#@#现在需要&%&%&修改字符串'  
str2 = str1.replace('$$$', ' ').replace('@#@#', ' ').replace('&%&%&', ' ')  
print (str2)  
# 方法2  
import re  
str1 = '你好$$$我正在学Python@#@#现在需要&%&%&修改字符串'  
str2 = re.sub('[$@#&%]+', ' ' ,str1)  
print (str2)  

10.2.3. 输出9×9乘法口诀表

# 此法会有多余的换行和末尾对于的空格  
for i in range(1,10):  
    for j in range(1,i+1):  
        print('{}×{}={}'.format(j,i,j*i),end=' ')  
    print('\n')  

# 更好的方法,没有对齐  

for i in range(1,10):  
    for j in range(1,i+1):  
        print('{}×{}={} '.format(j,i,j*i),end='')  
    print('')  

# 最好的方法 这里是对齐的。由此可见,'\t'是用来【显示】对齐的,但似乎len就是1  
for i in range(1,10):  
    for j in range(1,i+1):  
        print('{}×{}={}\t'.format(j,i,j*i),end='')  
    print('')  

# 最好的方法 这里是对齐的  
for i in range(1, 10):  
    for j in range(1, i+1):  
        print ("%dx%d=%d\t" % (j, i, i*j), end="")  
    print("")  

# 1×1=1  

# 1×2=2 2×2=4  

# 1×3=3 2×3=6 3×3=9  

# 1×4=4 2×4=8 3×4=12 4×4=16  

# 1×5=5 2×5=10 3×5=15 4×5=20 5×5=25   

# 1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36  

# 1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49  

# 1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64  

# 1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81  

# 1×1=1  
# 1×2=2 2×2=4  
# 1×3=3 2×3=6 3×3=9  
# 1×4=4 2×4=8 3×4=12 4×4=16  
# 1×5=5 2×5=10 3×5=15 4×5=20 5×5=25  
# 1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36  
# 1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49  
# 1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64  
# 1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81  
# 1×1=1  
# 1×2=2   2×2=4  
# 1×3=3   2×3=6   3×3=9  
# 1×4=4   2×4=8   3×4=12  4×4=16  
# 1×5=5   2×5=10  3×5=15  4×5=20  5×5=25  
# 1×6=6   2×6=12  3×6=18  4×6=24  5×6=30  6×6=36  
# 1×7=7   2×7=14  3×7=21  4×7=28  5×7=35  6×7=42  7×7=49  
# 1×8=8   2×8=16  3×8=24  4×8=32  5×8=40  6×8=48  7×8=56  8×8=64  
# 1×9=9   2×9=18  3×9=27  4×9=36  5×9=45  6×9=54  7×9=63  8×9=72  9×9=81  
# 1x1=1  
# 1x2=2   2x2=4  
# 1x3=3   2x3=6   3x3=9  
# 1x4=4   2x4=8   3x4=12  4x4=16  
# 1x5=5   2x5=10  3x5=15  4x5=20  5x5=25  
# 1x6=6   2x6=12  3x6=18  4x6=24  5x6=30  6x6=36  
# 1x7=7   2x7=14  3x7=21  4x7=28  5x7=35  6x7=42  7x7=49  
# 1x8=8   2x8=16  3x8=24  4x8=32  5x8=40  6x8=48  7x8=56  8x8=64  
# 1x9=9   2x9=18  3x9=27  4x9=36  5x9=45  6x9=54  7x9=63  8x9=72  9x9=81  

print(len('{}\t'.format(5*6)))  
print(len('{}\t'.format(5*60)))  
print(len('{}\t'.format(5*600)))  
print(len('{}\t'.format(5*6000)))  

# 3  
# 4  
# 5  
# 6  

10.2.4. 利润分段计算

请写出一个函数,当输入函数变量月利润为I时,能返回应发放奖金的总数。例如,输出“利润为100000元时,应发放奖金总数为10000元”。
其中,企业发放的奖金根据利润提成。
利润(I)低于或等于10万元时,奖金可提10%;
利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;
利润在20万元到40万元之间时,高于20万元的部分可提成5%;
利润在40万元到60万元之间时,高于40万元的部分可提成3%;
利润在60万元到100万元之间时,高于60万元的部分可提成1.5%;
利润高于100万元时,超过100万元的部分按1%提成。

def calcute_profit(I):  
    I = I / 10000  
    if I <= 10:  
        a = I * 0.01  
        return a * 10000  
    elif I <= 20 and I > 10:  
        b =0.25 + I * 0.075  
        return b * 10000  
    elif I <= 40 and I > 20:  
        c = 0.75 + I * 0.05  
        return c * 10000  
    elif I <= 60 and I > 40:  
        d = 0.95 + I * 0.03  
        return d * 10000  
    elif I <= 60 and I > 100:  
        e = 2 + I * 0.015  
        return e * 10000  
    else:  
        f = 2.95 + I * 0.01  
        return f * 10000  

I = int(input('净利润:'))  
profit = calcute_profit(I)  
print ('利润为%d元时,应发奖金总数为%d元' % (I, profit))  

def calcute_profit(I):  
    arr = [1000000,600000,400000,200000,100000,0] #这应该就是各个分界值了,把它们放在列表里方便访问  
    rat = [0.01,0.015,0.03,0.05,0.075,0.1] #这是各个分界值所对应的奖金比例值  
    r = 0                       #这是总奖金的初始值  
    for idx in range(0,6):      #有6个分界值当然要循环6次  
        if I > arr[idx]:  
            r = r + (I - arr[idx]) * rat[idx]  
            I = arr[idx]  
    return r  

I = int(input('净利润:'))  
profit = calcute_profit(I)  
print ('利润为%d元时,应发奖金总数为%d元' % (I, profit))  

10.2.5. 字典排序

用字典的值对字典进行排序,将{1: 2, 3: 4, 4:3, 2:1, 0:0}按照字典的值从大到小进行排序。

import operator  
x = {1: 2, 3: 4, 4:3, 2:1, 0:0}  
sorted_x = sorted(x.items(), key=operator.itemgetter(1))  
print (sorted_x)  

[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
对字典进行排序是【不可能】的,只有把字典【转换】成另一种方式才能排序。字典本身是无序的,但是如列表元组等其他类型是有序的,所以需要用一个元组列表来表示排序的字典。

可能遇到的问题

批量书合成一页还是每本书单独有序号|很多个人网站每个条目有自己的序号,按序号抓可不重不漏
正则表达式的引号问题|转义
网页可能不存在|try、except
匹配结果为0的情况|try、except
编译器vscode跑太慢|换回python自带IDLE,快很多
为啥跑着跑着就停了|
一级风险:原网站换
五级风险:原作者取消网盘链接

文章目录
  1. 1. 爬虫基础
    1. 1.1. 为什么要学
    2. 1.2. 类型
    3. 1.3. 技能
    4. 1.4. 应用场景
    5. 1.5. 流程图
  2. 2. 获取网页
    1. 2.1. 法律和道德、注意事项
    2. 2.2. 网页特点
      1. 2.2.1. 获取动态网页的真实地址
    3. 2.3. 抓包分析工具
    4. 2.4. API
    5. 2.5. 常用库
    6. 2.6. requests
    7. 2.7. urllib
      1. 2.7.1. 核心代码
      2. 2.7.2. eg.1 直接GET
      3. 2.7.3. eg.2 带参数的GET
      4. 2.7.4. eg.3 POST
      5. 2.7.5. 等效写法
      6. 2.7.6. 类方法解析
      7. 2.7.7. response
      8. 2.7.8. 设置代理
      9. 2.7.9. 设置headers
    8. 2.8. Selenium
    9. 2.9. 爬虫与反爬
      1. 2.9.1. 爬虫的尽头
      2. 2.9.2. 反爬的尽头
      3. 2.9.3. 网站为什么要“反爬虫”
      4. 2.9.4. 爬虫与反爬一览
      5. 2.9.5. 常见的反爬措施
        1. 2.9.5.1. 浏览器伪装技术
        2. 2.9.5.2. Cookie的使用
        3. 2.9.5.3. 访问频率
        4. 2.9.5.4. 登录限制
        5. 2.9.5.5. 通过Header封杀
        6. 2.9.5.6. JavaScript脚本动态获取网站数据
        7. 2.9.5.7. 验证码
        8. 2.9.5.8. ip限制
        9. 2.9.5.9. 服务器采集
        10. 2.9.5.10. 网站内容反爬
    10. 2.10. 编码
    11. 2.11. 爬虫进阶
    12. 2.12. 异常处理
  3. 3. 数据解析、清洗和组织
    1. 3.1. bs4
    2. 3.2. Xpath
  4. 2016 腾讯软件开发面试题(部分)
    1. 3.3. 解析器对比分析
  5. 4. 数据存储
    1. 4.1. 数据库
  6. 5. 高性能爬取策略
    1. 5.1. 性能
  7. 6. Scrapy分布式爬虫
    1. 6.1. 概述
    2. 6.2. 部署到Scrapinghub
    3. 6.3. 代码
    4. 6.4. 使用Scrapy填充数据库
    5. 6.5. Scrapyd
    6. 6.6. Scrapy项目
  8. 7. 数据分析
    1. 7.1. 可视化
    2. 7.2. NumPy
    3. 7.3. pandas
  9. 8. 框架
  10. 9. 项目实施
    1. 9.1. 框架搭建
    2. 9.2. 扩展技能
    3. 9.3. 后起
    4. 9.4. 加分项目
  11. 10. 实际爬虫
    1. 10.0.1. 简单的爬虫
    2. 10.0.2. 爬取豆瓣电影TOP250
    3. 10.0.3. 爬取动态网页
    4. 10.0.4. 通过Selenium模拟浏览器抓取
    5. 10.0.5. 深圳短租
  • 11. 相关参考
    1. 11.1. allitebooks
    2. 11.2. 其他
    3. 11.3. 中文书籍
    4. 11.4. 暂缺电子书
    5. 11.5. 网址
    6. 11.6. GitHub上的爬虫项目
      1. 11.6.1. 爬虫框架
      2. 11.6.2. 财经类
    7. 11.7. 公众号文章
    8. 11.8. 崔庆才的博客
      1. 11.8.1. 一、爬虫入门
      2. 11.8.2. 二、爬虫实战
      3. 11.8.3. 三、爬虫利器
      4. 11.8.4. 四、爬虫进阶
  • 12. 附录
    1. 12.1. 平台
    2. 12.2. 软件安装及环境配置
    3. 12.3. 第三方库
  • 13. 术语表
  • 1. 库的说明
    1. 1.1. re
      1. re.match
      2. re.search
      3. re.findall方法
      4. 为什么要在match的模式前加上r
    2. 1.2. bs4
  • 2. 典型应用
    1. 2.0.3. 简单的爬虫
    2. 2.0.7. 深圳短租
  • 3. 工具及资源列表
    1. 3.1. 网络下载
    2. 3.2. 书籍辅助
    3. 3.3. 端口
  • 4. 库
    1. 4.1. Python第三方库
  • 5. 附录
  • 6. 单项分析
    1. 6.1. 是什么
      1. 6.1.1. Selenium
      2. 6.1.2. 正则表达式
    2. 6.2. 为什么
      1. 6.2.1. 大数据及爬虫
      2. 6.2.2. Jupyter
    3. 6.3. 如何
      1. 6.3.1. 快捷
      2. 6.3.2. 获取动态网页的真实地址
    4. 6.4. 应用场景
      1. 6.4.1. 爬虫
    5. 6.5. 注意事项
  • 7. 多项关系
    1. 7.1. 流程图
      1. 7.1.1. 网络爬虫、数据采集
    2. 7.2. 分类树
    3. 7.3. 对比分析
    4. 7.4. 关系图
  • 8. 元学习(与物)
  • 9. 个人提升(与人)
  • 10. 代码清单
    1. 10.1. 基础语法
      1. 10.1.1. py
        1. 10.1.1.1. 类
      2. 10.1.2. 函数、类,可变与不可变
    2. 10.2. 基础算法
      1. 10.2.1. 循环打印输出从1到100的所有奇数
      2. 10.2.2. 字符串批量替换
      3. 10.2.3. 输出9×9乘法口诀表
      4. 10.2.4. 利润分段计算
      5. 10.2.5. 字典排序
    3. 可能遇到的问题
  • |