网络爬虫:就是抓取网页数据的程序。
网页三大特征:
1. 网页都有自己的URL(统一资源定位符)来进行定位,每个网页都有一个唯一的URL
2. 网页都用html(超文本标记语言)来描述页面信息。
3. 网页都用HTTP/HTTPS(超文本传输协议)协议来传输HTML数据。
爬虫的设计思路:
1. 首先设定需要爬取的网页的URL地址;
2. 通过HTTP协议来获取对应的HTML页面;
3. 提取HTML页面的信息:
a. 如果有用的数据,那就保存起来;
b. 如果是需要继续爬取的链接,重新指定第二步。
为什么要用Python做爬虫?
php、Java、C/C++、Python...
- PHP 虽然是世界上最好的语言,但是它天生不是用来做爬虫的,
而且多线程、异步支持比较差,并发能力较弱。
爬虫属于工具性程序,对速度和效率要求非常高。
- Java 的爬虫生态圈非常完善,Java语言本身比较笨重,代码量比较大。
相比而言,修改功能后会导致代码大量变动,开发成本和重构成本比较高。
- C/C++ 运行效率和性能几乎最强(汇编),学习成本太高,导致企业难以招人,
项目代码成型慢。用C/C++写爬虫,是能力的体现,但不是最好的选择。
- Python 语法优美,编写快速灵活,开发效率高,相关的HTTP请求库和HTML解析库非常丰富,
学习成本低。还有强大的爬虫框架Scrapy(twisted异步网络框架)、以及高效成熟的scrapy-redis分布式策略。
但是,因为是解释型语言,性能速度相对较差(但是,可以通过硬件弥补)。
课程介绍:
-1. Python基本语法知识 和 基本Web知识 已经搞定。
-2 HTML页面的抓取:
urllib、urllib2、requests三个HTTP请求处理库:
作用:通过处理,可以模拟浏览器发送HTTP请求,并获取服务器返回的HTML或其他响应页面。
-3 HTML页面的解析:
re、xpath、BeautifulSoup4、Jsonpath:
作用:使用某种描述性语言,指定一个匹配规则,来提取需要的页面数据,符合规则的数据,叫"匹配"。
-4 动态HTML处理/验证码的处理:
Selenium+PhantomJS: 模拟真实浏览器加载数据,js 、ajax等..
Tesseract OCR:光学字符识别系统,识别图像的内容,返回文本内容。
-5 Scrapy框架:
高定制性高性能的Python爬虫框架:
函数 - 类 - 模块/库/包 - 框架:包含了很多不同功能的模块
提供了数据下载、数据提取、数据存储、请求去重等,并且使用了twisted异步网络框架,下载速度非常快。
-6 scraoy-redis 分布式策略:
scrapy本身不支持分布式,scrapy-redis就是一套以redis数据库为核心的组件,让Scrapy具有了支持分布式的功能。所有的请求、请求去重指纹、数据都存储在同一个Redis数据库里,可以统一调度和分配。
-7 爬虫- 反爬虫 - 反反爬虫:
User-Agent、代理IP、验证码、动态数据加载等...
权衡:
数据成本 比较 人力成本 + 机器成本
爬虫和反爬虫之间的斗争,一定是爬虫获胜!
只要是真实用户可以浏览的网页数据,都可以用爬虫爬取下来。
毛主席说过:战略上蔑视、战术上重视。
Python自带的模块位置:
/usr/lib/python2.7/urllib2.py
通过pip install 安装的模块位置
/usr/local/lib/python2.7/site-packages
Ubuntu虚拟环境
workon spider_py2
gbk -> utf-8
str_utf8 = str_gbk.decode("utf-8").encode("gbk")
任何平台的任何编码格式都可以和Unicode互相转换。
https://www.baidu.com/s?wd=%E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98
ASCII
GBK
GB2312
https://tieba.baidu.com/f? kw=%E6%9D%8E%E6%AF%85 pn=50
page = 1 pn = 0
page = 2 pn = 50
page = 3 pn = 100
pn = (page - 1) * 50
for page in range(5):
pn = (page - 1) * 50
url =
^(.*):\s(.*)$
"\1" : "\2",
https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=20&limit=20
Ubuntu 用户变量:~/.bashrc
系统变量:/etc/profile
Mac : ~/.bash_profile
"Cookie" : "anonymid=j57kitk3-s3oosm; depovince=BJ; _r01_=1; JSESSIONID=abc0ilHulkVP1_GsQGo1v; wp_fold=0; jebecookies=80d78f96-6782-4834-b403-9ae24fd48c6a|||||; ick_login=f384a1df-b8eb-4d67-8cce-40fd44a82f0a; _de=BF09EE3A28DED52E6B65F6A4705D973F1383380866D39FF5; p=5d72640888585bb232a15470cf5710009; first_login_flag=1; [email protected]; ln_hurl=http://hdn.xnimg.cn/photos/hdn521/20140529/1055/h_main_9A3Z_e0c300019f6a195a.jpg; t=d1a9529285f098d933d0634c5da97a529; societyguester=d1a9529285f098d933d0634c5da97a529; id=327550029; xnsid=b17a55ab; loginfrom=syshome"
从计算机硬件角度:
计算机核心是CPU,承担了所有的运算任务。
单核CPU一次只能运行一个任务。AMD 物理核心
多核CPU一次能够运行多个任务。INTEL 虚拟核心
台式机I5 四核四线程
四个CPU核心,四个逻辑处理器,每个CPU核心都能运行一个任务
能够同时运行四个任务。
笔记本I5 双核四线程
二个CPU核心,四个逻辑处理器,每个CPU核心都能运行一个任务
能够同时运行四个任务。
CPU的线程 和 操作系统调度的线程 不是一个概念。
从操作系统角度:
进程:一个进程表示一个程序的执行活动;
线程:进行CPU运算最小调度单位。
进程之间是互相独立的,一个CPU同时只能运行一个进程(单核),其他进程就处于非运行状态。
进程可以包含的一个或多个的执行单元,叫线程。
举例:运行了一个爬虫程序,就会执行一个进程。CPU会有很多时间切片,给每个执行的线程分配一个时间切片,一个时间切片内只能执行一个任务。
同一个进程之间的内存空间是共享,不同进程之间的内存空间不共享。
一个线程在使用进程的内存空间时,其他线程必须等待结束,才能使用这块内存空间。
"互斥锁" 防止多个线程同时访问一块内存空间。
多线程:表示一个程序可以同时并发执行多个任务。
Python的多线程:
GIL(全局解释器锁):比如某个线程想要执行任务,必须获取GIL,在Python一个进程里,只有一个GIL。
线程必须拥有GIL才能执行任务,没有GIL的线程就不允许执行任务。
Python的多线程并不是真正的多线程,不能充分利用CPU的资源。
多进程:密集CPU运算(大量的并行运算),可以使用multiprocessing。
缺陷:多个进程之间的通信成本很高,对于需要进行大量数据通信的任务,就不适合多进程。
多线程:密集I/O处理(网络I/O,文件读写I/O),threading.Thread,multiprocessing.dummy、
缺陷:同一个CPU时间切片只能运行一个线程,优势:线程和线程之间的通信非常方便。
协程:处理了进程和线程之间切换和创建的开销,协程爬虫。genvent
for //div[@class=‘info‘]
//span[@class=‘title‘]/text()
//span[@class=‘rating_num‘]/text()
所有页码
//div[@class=‘paginator‘]/a/@href
https://movie.douban.com/top250
爬取优先级:
PC > 移动端 > HTML5 > APP
//input[@name=‘form_email‘]
form_password
soup = BeautifulSou(driver.page_source, "lxml")
# 主播名 class
soup.find_all("span", attrs = {"class" : "dy-name ellipsis fl"})
# 房间名 class
soup.find_all("h3", attrs = {"class" : "ellipsis"})
# 观众人数
soup.find_all("span", attrs = {"class" : "dy-num fr"})
#下一页 class
driver.find_element_by_class_name("shark-pager-next").click()
# 最后一页的下一页
# 等于 -1 表示没到最后一页
# 不等于 -1 表示到了最后一页
if driver.page_source.find("shark-pager-disable-next") != -1:
break
Scrapy 部分:
第一阶段:urllib2/requests re lxml BeautifulSoup json/jsonpath...
瑞士军刀...
第二阶段:Scrapy:擅长处理大量页面
屠龙刀...
爬虫的八字真言:模拟请求,处理响应。
工作的好伙伴:
baidu:遇到问题百度一下
google:百度不到就google一下
stackoverflow:程序员的问答网站
官方文档
scrapy各组件工作:
spider : 接收响应,经过提取后返回:1. 继续发送的请求->调度器 2. 需要存储的数据-> 管道
调度器:将请求排序、去重、入队列、出队列。
下载器:发送请求,返回响应给spider
管道:接收需要存储的数据,处理这些数据(存数据库、存json、存csv....)
下载中间件:请求发送前添加代理、切换user-agent等处理...
http://www.itcast.cn/channel/teacher.shtml
//div[@class=‘li_txt‘]
h3
h4
p
更换IP方式:
Ip :电脑Ip(代理池)
Tor :暗网,访问慢,动态Ip
ADSL :拨号上网,动态Ip(断开重新连接,会更换IP)
必须背下来的命令:
# 创建一个Scrapy项目,名为XXX
scrapy startproject XXX
# 创建一个Scrapy.Spider类的爬虫,爬虫名为xxx,所属网站域名为xxx.com
scrapy genspider xxx "xxx.com"
# 执行爬虫xxx,表示启动爬虫
scrapy crawl xxx
# 执行爬虫,并按json格式存储结果,默认Unicode编码
scrapy crawl itcast -o itcast.json
# 执行爬虫,并按csv格式存储结果
scrapy crawl itcast -o itcast.csv
scrapy.Spider类爬虫必备的参数:
# 导入scrapy
import scrapy
class ItcastSpider(scrapy.Spider):
# 当前爬虫文件的爬虫名,对应执行爬虫的爬虫名称
name = "xxx"
# 允许当前爬虫爬取的网站域名范围,不在域名列表内的网页将不爬取
allowed_domains = [‘xxx.com‘, ‘xxxx.com‘]
#启动爬虫后,开始爬取的第一批url地址将从start_urls里获取
start_urls = [‘http://www.xxx.com/xxxxxx.html‘]
# scrapy.Spider类的爬虫,返回的响应对象默认由parse()函数处理
def parse(self, response):
print response.body
scrapy项目使用流程:
1. 创建项目: scrapy startproject
2. 编写item : item.py 定义存储数据的字段
3. 编写spider: spiders/spider.py 用来发送start_urls请求,并 parse() 处理响应提取数据, yield item(交给管道) yield Request(交给调度器去下载)
4. 编写pipelines:pipelines.py 处理通过spider返回的item数据
5. 启用管道: settings.py ITEM_PIPELINES 启用自定义的管道
6. 编写middlewares(如果有的话): middlewares 处理发送前的请求(添加代理)
启动MongoDB服务: 储存数据:字典格式
sudo mongod
启动MongoDB Shell
sudo mongo
1. 查看当前所有数据库
show dbs
2. 切换指定数据库
use Douban
3. 查看当前数据库下所有的表
show collections
> DoubanMovie
4. 查看当前数据库下指定表的数据
db.DoubanMovie.find()
MongoDB
Redis
mysql
pip -V
sudo pip install pip --upgrade
sudo pip install scrapy --upgrade
Scrapyd 的远程部署和监控
1. 安装Scrapyd
sudo pip install scrapyd # 安装scrapyd服务
sudo pip install scrapyd-client # 安装scrapyd客户端
2. 启动scrapyd服务
scrapyd # 启动服务,端口号 6800
远程连接: 打开浏览器,192.168.105.99:6800
3. 部署scrapy项目到scrapyd上的配置
# 1. scrapyd的配置名
[deploy:scrapy_Tencent]
# 2. 启动scrapyd服务的远程主机ip,localhost默认本机的
url = http://localhost:6800/
#url = http:192.168.xx.xxx:6800
#- 3.项目名称
project = Tencent
4. 将scrapy项目部署到scrapyd上
# -p 执行项目名,将Tencent按指定的配置信息部署到scrapyd
scrapyd-deploy scrapy_Tencent -p Tencent
5. 启动项目下指定的爬虫
curl http://localhost:6800/schedule.json -d project=Tencent -d spider=tencent
{"status": "ok", "jobid": "2f240b1171bc11e7ae5aa45e60e36247", "node_name": "PowerMac.local"}
6. 停止项目下指定的爬虫
curl http://localhost:6800/cancel.json -d project=Tencent -d job=2f240b1171bc11e7ae5aa45e60e36247
7. 停止scrapyd的服务
Control + C
云墙