爬虫介绍

一、爬虫介绍:

什么是爬虫?

爬虫就是通过编写程序模拟浏览器上网,然后让其去互联网上抓取数据的过程。

哪些语言可以实现爬虫

1.php:可以实现爬虫。php被号称是全世界最优美的语言(当然是其自己号称的,就是王婆卖瓜的意思),但是php在实现爬虫中支持多线程和多进程方面做的不好。
2.java:可以实现爬虫。java可以非常好的处理和实现爬虫,是唯一可以与python并驾齐驱且是python的头号劲敌。但是java实现爬虫代码较为臃肿,重构成本较大。
3.c、c++:可以实现爬虫。但是使用这种方式实现爬虫纯粹是是某些人(大佬们)能力的体现,却不是明智和合理的选择。
4.python:可以实现爬虫。python实现和处理爬虫语法简单,代码优美,支持的模块繁多,学习成本低,具有非常强大的框架(scrapy等)且一句难以言表的好!没有但是!

爬虫的分类

1.通用爬虫:
通用爬虫是搜索引擎(Baidu、Google、Yahoo等)“抓取系统”的重要组成部分。主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。 简单来讲就是尽可能的;把互联网上的所有的网页下载下来,放到本地服务器里形成备分,在对这些网页做相关处理(提取关键字、去掉广告),最后提供一个用户检索接口。
.
搜索引擎如何抓取互联网上的网站数据?
1.门户网站主动向搜索引擎公司提供其网站的url
2.搜索引擎公司与DNS服务商合作,获取网站的url
3.门户网站主动挂靠在一些知名网站的友情链接中

2.聚焦爬虫:
聚焦爬虫是根据指定的需求抓取网络上指定的数据。例如:获取豆瓣上电影的名称和影评,而不是获取整张页面中所有的数据值。

robots.txt协议

如果自己的门户网站中的指定页面中的数据不想让爬虫程序爬取到的话,那么则可以通过编写一个robots.txt的协议文件来约束爬虫程序的数据爬取。robots协议的编写格式可以观察淘宝网的robots(访问www.taobao.com/robots.txt即可)。但是需要注意的是,该协议只是相当于口头的协议,并没有使用相关技术进行强制管制,所以该协议是防君子不防小人。但是我们在学习爬虫阶段编写的爬虫程序可以先忽略robots协议。

反爬虫

门户网站通过相应的策略和技术手段,防止爬虫程序进行网站数据的爬取。

反反爬虫

爬虫程序通过相应的策略和技术手段,破解门户网站的反爬虫手段,从而爬取到相应的数据。

二、requests模块学习

什么是requests模块

requests模块是python中原生的基于网络请求的模块,其主要作用是用来模拟浏览器发起请求。功能强大,用法简洁高效。在爬虫领域中占据着半壁江山的地位。

使用requests模块的优势:

自动处理url编码
自动处理post请求参数
简化cookie和代理操作

通过5个基于requests模块的爬虫项目对该模块进行学习和巩固

基于requests模块的get请求
--- 需求:爬取搜狗指定词条搜索后的页面数据
基于requests模块的post请求
--- 需求:登录豆瓣电影,爬取登录成功后的页面数据
基于requests模块ajax的get请求
--- 需求:爬取豆瓣电影分类排行榜 https://movie.douban.com/中的电影详情数据
基于requests模块ajax的post请求
--- 需求:爬取肯德基餐厅查询http://www.kfc.com.cn/kfccda/index.aspx中指定地点的餐厅数据
综合练习
--- 需求:爬取搜狗知乎指定词条指定页码下的页面数据

爬虫小项目联系:

#爬取搜狗首页的页面数据
#1.指定url
#2.基于requests模块的请求发送
#3.获取响应对象中的数据值
#4.持久化存储

import requests

url = 'https://www.sogou.com/'

#2.调用get方法,该方法就可以根据指定的url发起请求,返回一个响应对象
response = requests.get(url=url,proxies={'https':'121.139.218.165:31409'})

#3.text属性就可以将响应对象中的数据值进行获取,text属性返回的数据类型是str
page_text = response.text
with open('./sogou.html','w',encoding='utf-8') as fp:
    fp.write(page_text)

response.text # 返回的数据类型是str
response.content #返回的是二进制的页面数据
response.status_code # 返回状态码
response.url # 返回url
response.encoding #返回的是响应对象中存储数据的原始编码格式

//  爬取搜狗指定词条搜索后的页面数据
word = input('enter a word:')

url = 'https://www.sogou.com/web?'
#如果url携带了参数,我们最好需要将参数封装到一个字典中
param = {
    'query':word
}
#将封装好的参数作业到请求中
response = requests.get(url=url,params=param)

page_text = response.text

fileName = word+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
    fp.write(page_text)
// 需求:登录豆瓣电影,爬取登录成功后的页面数据
import requests
url = 'https://www.douban.com/accounts/login'

#对post请求携带的参数进行字典封装
data = {
    "source": "index_nav",
    "form_email": "15027900535",
    "form_password": "bobo@15027900535",
}
response = requests.post(url=url,data=data)

page_text = response.text

with open('douban.html','w',encoding='utf-8') as fp:
    fp.write(page_text)
#爬取豆瓣电影分类排行榜 https://movie.douban.com/中的电影详情数据
import requests
url = 'https://movie.douban.com/j/chart/top_list?'

param = {
    "type": "13",
    "interval_id": "100:90",
    "action": "",
    "start": "100",
    "limit": "20",
}
response = requests.get(url=url,params=param,proxies={'https':'121.139.218.165:31409'})

print(response.text)
// 需求:爬取肯德基餐厅查询http://www.kfc.com.cn/kfccda/index.aspx中指定地点的餐厅数据
import requests

url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
city = input('enter a city:')
data = {
    "cname":"",
    "pid":"",
    "keyword":city,
    "pageIndex":"2",
    "pageSize":"10",
}
response = requests.post(url=url,data=data)

response.text
#需求:爬取博客园指定页面下的页面数据
import requests
import os
url = 'https://www.cnblogs.com/#p'

#新建一个文件夹
if not os.path.exists('boke'):
    os.mkdir('boke')

#提供一组页码的范围
start_page = int(input('enter a start page:'))
end_page = int(input('enter a end page:'))

for page in range(start_page,end_page+1):
    url =url + str(page)
    response = requests.get(url=url,proxies={'https':'121.139.218.165:31409'})
    page_text = response.text
    
    fileName = str(page)+".html"
    filePath = './boke/'+fileName
    with open(filePath,'w',encoding='utf-8') as fp:
        fp.write(page_text)
        print('第%d页下载成功'%page)

三、反爬

反爬机制:UA验证
反反爬机制:UA身份的伪装
流程:封装一个请求头字典(UA)。将该字典作用到请求对象中

自制定请求头信息
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36"
}
response = requests.post(url=url,data=data,headers=headers)

四、三种数据解析方式学习

1. re模块解析方式


提取出python
key="javapythonc++php"
re.findall('python',key)[0]

提取出hello world
key="<html><h1>hello world<h1></html>"
re.findall('<h1>(.*)<h1>',key)[0]

提取170
string = '我喜欢身高为170的女孩'
re.findall('\d+',string)[0]

提取出http://和https://
key='http://www.baidu.com and https://boob.com'
re.findall('https?://',key)

提取出hello
key='lalala<hTml>hello</HtMl>hahah' #输出<hTml>hello</HtMl>
re.findall('<[hH][tT][mM][lL]>(.*)</[hH][tT][mM][lL]>',key)[0]

提取出hit. :贪婪模式:尽可能多的匹配数据
key='bobo@hit.edu.com'#想要匹配到hit.
re.findall('h.*?.',key)

匹配sas和saas
key='saas and sas and saaas'
re.findall('sa{1,2}s',key)

匹配出i开头的行
string = '''fall in love with you
i love you very much
i love she
i love her'''
re.findall('^i.*',string,re.M)

匹配全部行
string1 = """<div>细思极恐
你的队友在看书
你的闺蜜在减肥
你的敌人在磨刀
隔壁老王在练腰
</div>"""
re.findall('.*',string1,re.S)

// 项目需求:爬取糗事百科指定页面的糗图,并将其保存到指定文件夹中
import requests
import re
import os

if not os.path.exists('qiutu'):
    os.mkdir('qiutu')
    
url = 'https://www.qiushibaike.com/pic/'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 
      (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36'
}
response = requests.get(url=url,headers=headers)

page_text = response.text

#4.数据解析(正则):图片
img_url_list = re.findall('<div class="thumb">.*?<img src="(.*?)".*?>.*?</div>',page_text,re.S)
for img_url in img_url_list:
    #获取的是图片完整的url
    img_url = "https:"+img_url
    #针对图片url发起指定的请求,获取图片二进制的数据值
    img_response = requests.get(url=img_url,headers=headers)
    #获取响应对象中图片二进制的数据值
    img_data = img_response.content
    imgName = img_url.split('/')[-1]
    imgPath = 'qiutu/'+imgName
    #将图片数据存储到磁盘
    with open(imgPath,'wb') as fp:
        fp.write(img_data)
        print(imgName+'下载成功')

2. 基于xpath解析方式


基于xpath解析的实现原理:
1.实例化一个etree对象,然后将页面数据封装到该对象
2.调用etree对象中的xpath函数实现解析操作
3.将指定的xpath表达式作用的xpath函数中

常用xpath表达式
.
属性定位:
#找到class属性值为song的div标签
//div[@class="song"]
层级&索引定位:
#找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
//div[@class="tang"]/ul/li[2]/a
逻辑运算:
#找到href属性值为空且class属性值为du的a标签
//a[@href="" and @class="du"]
模糊匹配:
//div[contains(@class, "ng")]
//div[starts-with(@class, "ta")]
取文本:
# /表示获取某个标签下的文本内容
# //表示获取某个标签下的文本内容和所有子标签下的文本内容
//div[@class="song"]/p[1]/text()
//div[@class="tang"]//text()
取属性:
//div[@class="tang"]//li[2]/a/@href

使用xpath表达式进行数据解析步骤
1.下载:pip install lxml
2.导包:from lxml import etree
3.将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点
  2.1 本地文件:
tree = etree.parse(文件名)
tree.xpath("xpath表达式")
  2.2 网络数据:
tree = etree.HTML(网页内容字符串)
tree.xpath("xpath表达式")

// 需求:爬取boss直聘的岗位信息

import requests
from lxml import etree

job = input('enter a job:')
url = 'https://www.zhipin.com/job_detail/?'
param = {
    'query':job
}

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) 
      Chrome/69.0.3497.81 Safari/537.36'
}
response = requests.get(url=url,params=param,headers=headers)
page_text = response.text

#解析:
#1.获取所有岗位的链接
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="job-list"]/ul/li')
#只用Element类型的对象可以调用xpath方法
for li in li_list:
    job_url = li.xpath("./div/div[1]/h3/a/@href")[0]# .li对象表示的局部页面内容
    job_url = "https://www.zhipin.com" + job_url
    
    #对job_url发起请求,获取岗位对应的详情页面
    secondPage_text = requests.get(url=job_url,headers=headers).text
    
    tree = etree.HTML(secondPage_text)
    #解析岗位名称
    jobName = tree.xpath('//div[@class="info-primary"]/div[2]/h1/text()')[0]
    salary = tree.xpath('//div[@class="info-primary"]/div[2]/span/text()')[0].strip('\n\t')
    detail = tree.xpath('//div[@class="info-primary"]/p//text()')[0]
    company = tree.xpath('//div[@class="info-company"]/h3/a/text()')[0]
    jobDesc = tree.xpath('//div[@class="detail-content"]/div[1]/div//text()')[0]
    
    #持久化存储mysql/redis等

3、BeautifulSoup解析


使用流程:

  • 导包:from bs4 import BeautifulSoup
  • 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容
    (1)转化本地文件:
    - soup = BeautifulSoup(open('本地文件'), 'lxml')
    (2)转化网络文件:
    - soup = BeautifulSoup('字符串类型或者字节类型', 'lxml')
    (3)打印soup对象显示内容为html文件中的内容

基本使用:

(1)根据标签名查找
soup.a 只能找到第一个符合要求的标签
(2)获取属性
- soup.a.attrs 获取a所有的属性和属性值,返回一个字典
- soup.a.attrs['href'] 获取href属性
- soup.a['href'] 也可简写为这种形式
(3)获取内容
- soup.a.string
- soup.a.text
- soup.a.get_text()
【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
(4)find:找到第一个符合要求的标签
- soup.find('a') 找到第一个符合要求的
- soup.find('a', title="xxx")
- soup.find('a', alt="xxx")
- soup.find('a', class_="xxx")
- soup.find('a', id="xxx")
(5)find_all:找到所有符合要求的标签
- soup.find_all('a')
- soup.find_all(['a','b']) 找到所有的a和b标签
- soup.find_all('a', limit=2) 限制前两个
(6)根据选择器选择指定的内容
select:soup.select('#feng')
- 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
- 层级选择器:
div .dudu #lala .meme .xixi 下面好多级
div > p > a > .lala 只能是下面一级
【注意】select选择器返回永远是列表,需要通过下标提取指定的对象

import requests
from bs4 import BeautifulSoup

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 
    (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}

def parse_content(url):
    # 获取标题正文页数据
    page_text = requests.get(url, headers=headers).text
    soup = BeautifulSoup(page_text, 'lxml')
    # 解析获得标签
    ele = soup.find('div', class_='chapter_content')
    content = ele.text  # 获取标签中的数据值
    return content

if __name__ == "__main__":
    url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
    reponse = requests.get(url=url, headers=headers)
    page_text = reponse.text

    # 创建soup对象
    soup = BeautifulSoup(page_text, 'lxml')
    # 解析数据
    a_eles = soup.select('.book-mulu > ul > li > a')
    print(a_eles)
    cap = 1
    for ele in a_eles:
        print('开始下载第%d章节' % cap)
        title = ele.string
        content_url = 'http://www.shicimingju.com' + ele['href']
        content = parse_content(content_url)

        with open('./sanguo.txt', 'w') as fp:
            fp.write(title + ":" + content + '\n\n\n\n\n')
            print('结束下载第%d章节' % cap)
        cap += 1
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,367评论 6 532
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,001评论 3 413
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 175,213评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,535评论 1 308
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,317评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,868评论 1 321
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,963评论 3 440
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,090评论 0 285
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,599评论 1 331
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,549评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,712评论 1 367
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,233评论 5 356
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,961评论 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,353评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,607评论 1 281
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,321评论 3 389
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,686评论 2 370

推荐阅读更多精彩内容