基本语法
构造url网页链接常用字符串处理
str.split('.')#不添加默认按空格tab分割'www.baidu.com'-->'www','baidu','com'
str.replace('要修改的','要用来替代的')
str.strip()#去掉前后端(两侧)空格
'{提取的格式化内容}str'.format('选项')#常用在连接最后的搜索内容'https://www.pexels.com/search/{}/'format(content)
函数
#手机号隐私展示:156****9354(输入时完整)
hiding_num=num.replace(number[3:7],'*'*4)
数据结构
列表
列表在爬虫中的常见作用:构造多个URL,爬取的数据,大多数都为列表数据结构
特性:每个元素都是可变的,有序,可以容纳所有对象[字符串,整数,浮点数,元组,函数,布尔值,集合等];列表的增删改查在爬虫中用的少
常用多重循环
zip前后变量要一致
names=['小a''小b','小c']
ages=[12,13,14]
for name,age in zip(names,ages):
print(name,age)
#result 小a 12 #小b 13 #小c 14
请求多个网页,通常情况下会把网页存到列表中,循环依次取出并访问爬取数据,手动存入花费时间,代码冗余,通过列表推导式构造列表
http://bj.xiaozhu.com/search-duanzufang-p1-0
http://bj.xiaozhu.com/search-duanzufang-p2-0
http://bj.xiaozhu.com/search-duanzufang-p3-0
......
urls=['http://bj.xiaozhu.com/search-duanzufang-p{}-0'.format(number)for num in range(1,14)]
for url in urls:
print(url)
字典:插入MongoDB数据库需用字典结构
元组(不能修改只能查看)和{集合}很少用到
文件操作
open(name[,model[,buffering]]) #文件名作为唯一强制参数
r w a b + #model模式
f=open('.....路径....','w+')
f.write() #写入
content=f.read()#清理缓冲和文件安全 #读取
面向对象
class Bike:
compose=['frame','wheel','pedal']
my_bike=Bike() #类的实例化 my_bike 类的实例
your_bike=Bike()
print(my_bike.compose) #'.'加上类的属性,类属性的引用
print(your_bike.compose)
my_bike.other='basket' #给类的实例属性进行赋值,实例属性
print(my_bike.other)
#实例方法:方法就是函数,方法是对实例进行使用的,所以又叫实例方法,对bike类而言,它的方法就是骑行。
class Bike:
#----------------实例方法--------------
compose=['frame','wheel','pedal']
def use(self):#self参数就是实例本身,可以有参数
print('u r riding')#对实例进行使用的,实例方法
my_bike=Bike()
my_bike.use()#实例方法
#----------------实例方法可以添加参数-----------
def use(self,time):
print('u ride {}m'.format(time*100))
my_bike=Bike()
my_bike.use(10)
#-------__init__()创造实例时,不需要引用也会被自动执行---------
class Bike:
compose=['frame','wheel','pedal']
def __init__(self):
self.other='basket'
def use(self,time):
print('u ride {}m'.format(time*100))
my_bike=Bike()
print(my_bike.other)
继承
2nd 爬虫原理和网页构造
网络连接:基本过程
爬虫原理:基本原理和过程
chrome浏览器:使用chrome认识网页结构和查询网页信息
网络连接
计算机(购买者)带着请求头和消息体(硬币和所需饮料)向服务器(自动售货机)发起依次request请求(购买),响应的服务器(自助售货机)返回本计算机相应的HTML文件作为Response(相应的商品)
request (请求头&请求体)
response (HTML文件)
爬虫原理
爬虫要做的两件事:
- 模拟计算机对服务器发起的Request请求
- 接收服务端的response内容并解析,提取所需的信息
一次请求回应不能批量获取数据–>设计爬虫流程(多页面 / 跨页面)
多页面:
1.手动翻页并观察各网页的URL构成特点,构造出所有页面的URL存入列表中
2.根据URL列表依次循环取出URL
3.定义爬虫函数
4.循环调用爬虫函数,存储数据
5.循环完毕,结束爬虫程序
【插图】
跨页面
1.定义爬取函数爬取列表页的所有专题的URL
2.将专题URL存入列表中(种子URL)
3.定义爬取详细页面数据函数
4.进入专题详细页面爬取详细页数据
5.存储数据,循环完毕,结束爬虫程序
网页构造
简单介绍网页构造,前段语法不做解释:
HTML文件;CSS样式;的是JavaScript代码
客户浏览的网页是浏览器渲染后的结果,浏览器就像翻译官,把HTML,CSS和JavaScript代码翻译后得到用户使用的网页界面。网页是房子,HTML是框架和格局(几室几厅),CSS就是样式(地板,房漆),JavaScript是里面的电器。
1st爬虫程序
Python第三方库:概念及安装方法
Requests库:使用原理和方法
BeautifulSoup库:使用原理和方法
Requests和BeautifulSoup的组合
python第三方库
(不用底层思想,用最少的代码写最多的功能,不用铁矿石橡胶造车,只用拼装)
File /project setting
Requests:请求网站获取网页数据
import request
res=requests.get('http://bj.xiaozhu.com/')
print(res)
#结果为<Response [200]>,说明请求成功,若404 400 失败
print(res.txt)#打印源代码
伪装请求头User-Agent F12代开开发者工具,刷新网页后找到User-Agent进行复制Mozilla/5.0
import Requests
headers={User-Agent:'Mozilla/5.0'}
res=requests.get('http://bj.xiaozhu.com',headers-headers)
print(res.text)
Requests库
不仅有get方法,还有post方法(用于提交表单来爬取需要登陆才能获得数据的网站)
Requests常见错误异常:
1.ConnectionError异常,网络问题(DNS查询失败,拒绝链接等)
2.Response.raise_for_status()抛出一个HTTPError异常,原因为HTTP请求返回了不成功的状态码(网页不存在,返回404错误)
3.Requests抛出一个Timeout异常,原因为请求超时
4.Requests抛出一个TooManyRedirects异常,请求超过设定的最大重定向次数
requests.exceptions.RequestException当发现这些错误或异常进行代码修改重新再来时,爬虫的程序又重新开始运行,数据重新爬取,对于效率和质量来说都是不利的。通过try避免异常
import Requests
headers={User-Agent:'Mozilla/5.0'}
res=requests.get('http://bj.xiaozhu.com',headers-headers)
try:
print(res.text)
except ConnectionError: #出现错误会执行下面的操作
print('拒绝连接')
通过try和except,如果请求成功了,会打印网页的源代码。如果connectionError异常,打印‘拒绝连接’,这样程序就不会报错,而是给编程一个提示,不会影响下面代码的运行。
BeutifulSoup库
主要功能:把源代码解析为Soup文档,以便过滤提取数据
import requests
from bs4 import BeautifulSoup
headers={'User-Agent':'Mozilla/5.0'}
res=requests.get('http://bj.xiaozhu.com/',headers=headers)
soup=BeautifulSoup(res.text,'html.parser')#对返回的结果进行解析
print(soup.prettify())
#看上去类似,但是标准缩进,为结构化的数据,为数据的过滤提取做好准备
支持HTML解析器外,还支持一些3rd方解析器。
解析得到的Soup文档可以用==find() find_all() selector()==方法定位需要的元素
find_all(tag,attributes,recursive,text,limit,keywords) #返回集合
soup.find_all('div',"item")##查找div标签,class="item"
soup.find_all('div',class="item")
soup.find_all('div',attrs={"class":"item"})#attrs参数定义一个字典参数
find(tag,attributes,recursive,text,keywords) #返回一个
soup.selector(div.item > a > h1) #括号内容通过Chrome复制得到 中国 > 湖南省 > 长沙市
#源代码选中元素右击Copy selector
#page_list > ul > li:nth-child(1) > div.result_btm_con.lodgeunitname > div:nth-child(1) > span > i
print(price.get_text())#从[<i>898</i>]即可获得中间的文字
import requests
from bs4 import BeautifulSoup
headers={'User-Agent':'Mozilla/5.0'}
res=requests.get('http://bj.xiaozhu.com/',headers=headers)
soup=BeautifulSoup(res.text,'html.parser')#对返回的结果进行解析
price=soup.select('page_list > ul > li:nth-child(1) > div.result_btm_con.lodgeunitname > div:nth-child(1) > span > i')
prices=soup.select('page_list > ul > div.result_btm_con.lodgeunitname > div:nth-child(1) > span > i')
print('单个价格:',price )
print('×××××××××××××××××'\n'多个价格:')
for price in prices:
print(price.get_text())#从[<i>898</i>]即可获得中间的文字
项目1:小猪网页爬取
任务要求: 13页网址;爬取进入详细页面的网址链接,进而爬取数据:标题,地址,价格,房东名称,房东性别,房东头像的链接
代码分析:
- 导入Requests BeautifulSoup time
- 通过Chrome浏览器开发者工具,复制User-Agent用于伪装浏览器,便于爬虫的稳定性
- 定义get_links()函数,获取进入详细页的链接
传入URL后,进行请求和解析。通过Chrome的检查并Copy Selector,找到进入详细页的URL链接,但URl链接并不是嵌套在标签中,而是在标签属性的信息中
get_text()获取标签中的文本属性,标签属性通过get('attr ‘)方法获得,URL在href中,用get(’ href ')得到
最后调用get_info()函数,转入的参数为获取到的网页详细页的链接 - get_info()函数,用于获取网页信息并输出信息
传入URL后,进行请求和解析。通过chrome浏览器的检查并copy selector,获取相应的信息,由于信息数据为列表结构,可以通过多重循环,构造出字典数据,输出并打印出来 - judgment_sex()函数,用于判断房东的性别
项目2:酷狗TOP500首
思路分析:500首歌一页22首,总共23个URL;排名+歌手+歌曲名+歌曲时间
代码分析:
1.导入需要的库,requests beautifulsoup time
2.伪装User-Agent的header
3.定义get_info()函数,用于获取网页信息并输出;传入URL后,进行请求和解析。通过copy selector获取信息,从列表转换成字典输出打印
4.程序主入口,通过对网页URL的观察,利用列表推导式构造23个URL,并依次调用get_info()函数,time.sleep()防止请求过快被禁
第四章 正则表达式
知识点:正则常用符号,re模块,requests和re的组合
4.1 正则常用功能符号
4.1.1 一般字符
. 匹配任意单个字符 abc aic a&c -->a.b (不包括换行符)
\ 转义字符(特殊含义转字面意思).–>.(而不是匹配所有字符)
[…] 字符集(对应字符集中的任意字符)a[bcd]–>ab ac ad
\d 数字 [0-9]
\D 非数字 [^0-9]
\s 空白(空格,tab,换页符等)[\f\n\r\t\v]
\S 任一非空 [^\f\n\r\t\v]
\w
\W
*
+
?
{m}
{m,n}
^
$
\A
\Z
…没有复制过来完,直接记就行了
4.2 re模块及其用法
4.2.1 search() 第一个符合规则的内容,返回一个正则表达对象
re.match(pattern,string,flags=0)
pattern 匹配的正则表达式
string 要匹配的字符串
flags控制匹配方式,是否区分大小写,多行匹配等
infos=re.search('\d+','one1two2three3')-->#正则表达式对象
print(infos.group())-->1#第一个
4.2.2 sub() 函数(相当于字符串中的replace但是更灵活,能用正则匹配)
re.sub(pattern,repl,string,count=0,flags=0)
re.sub('\D','','123-456-789')#替换非数字
repl 替换的字符串
string 原始字符串
counts 最大次数,默认0替换所有匹配
flags 控制大小写是否区分,多行匹配等
4.2.3 findall()使用频率最多 匹配所有
infos=re.findall('\d+','one1two2three3')-->'1','2','3'
#-----------示例-----------------
import re,requests
res=requests.get('http://bj.xiaozhu.com/')
prices=re.findall('.......')
for price in prices:
print(price)
#用正则代码更简单,少了解析数据这一步,通过requests库请求的HTML文件就是字符串类型,代码可以直接通过正则表达式提取数据
4.2.4 re模块修饰符
…直接复制记住大小写,多行匹配
a='''<div>指数
</div>'''
word01=re.findall('<div>(.*?)</div>',a)#-->[]
word02=re.findall('<div>(.*?)</div>',a,re.S)#-->['指数\n'] word02.strip()去除换行符
print(word01,word02)
4.3 综合案例 --项目3 爬斗破苍穹 全文小说
技术点:requests库和正则表达式,存储到本地文件
思路分析:2 5 6 7 8–>从第一章开始构造URL,中间有404跳过不爬取,txt存储
代码分析:
1.需要的库 requests re time (正则不用BeautifulSoup解析网页数据)
2.User-Agent请求头伪装
3.新建TXT文档,用于存储文本信息
4.get_info()函数,获取信息并存储信息。传入URL后,进行请求,通过正则表达式定位到小说的文本内容,并写入TXT文档中。
5.程序的主入口,通过对网页URL的观察,使用列表推导式构造所有小说URL,并一次调用get_info()函数,time.sleep()防止访问过快被禁
4.4.综合案例2–爬取糗事百科段子信息
思路分析:提取对应页面的URL特点;需要信息:用户ID,等级,性别,段子文字,好笑数量,评论数量;文件存储在TXT
代码分析:
1.需要的库 requests time re
2.User-Agent (headers)
3.info_lists空列表,用于爬取的数据,字典结构
4.judgement_sex()函数,用于判断用户的性别
5.get_info()获取网页信息传入info_lists列表中。传入URL后,进行请求。以获取用户ID信息为例,通过源代码ctrl+f输入用户ID查看相应位置。信息处理方法有不同。×××××有难度,30号细看联网匹配是否正确
6.主入口,通过列表推导式构造35个URL,并依次调用get_info()函数存入TXT文档
第五章 Lxml库与Xpath语法
etree库 把HTML文档解析为Element对象,输出解析过的HTML文档,会自动修复
lxml比beautifulsoup更快,学会Xpath语法并通过Xpath语法提取所需的网页信息,通过案例 与正则和beautifulsoup的性能对比。
from lxml import etree
text='''
<div class="ui segment">
piossdfkjawoepuadjf[awpeiwoeihf;asdjgoywuprfiashdfhoew9ufhsdlhfpasudfoiajeohfiaspuefaskhdf;lasjkdf
</div>
<div class="ui segment">
piossdfkjawoepuadjf[awpeiwoeihf;asdjgoywuprfiashdfhoew9ufhsdlhfpasudfoiajeohfiaspuefaskhdf;lasjkdf
</div>
'''
html=etree.HTML(text) #-->element
res=etree.tostring(html) #解析
from lxml import etree
html=etree.parse('flower.html')
res=etree.tostring(html,pretty_print=True)
print(res)
Xpath语法:在XML文档中查找信息的语言
5.2.1节点关系
父节点
<papa>
<son></son>
</papa>
子节点
同胞节点
先辈节点
后代节点
5.2.2 节点选择
nodename | 此节点的所有子节点 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
. | 当前节点 |
… | 当前节点的父节点 |
@ | 选取属性 |
#段子id
'''
获取用户ID
'//div[@class="article block untagged mb15 typs_hot"]'-->每个段落的循环点
//*[@id="qiushi_tag_122191811"]/div[1]/a[2]/h2-->前面循环不用已遍历不用重复,div[1]/a[2]/h2-->用户ID
'''
import requests
from lxml import etree
headers={'User-Agent':'Mozilla/5.0'}
url='http://www.qiushibaike.com/text/'
res=requests.get(url,headers=headers)#通过headers和url用requests.get方法得到响应
selector=etree.HTML(res.text)#用HTML解析响应内容
url_infos=selector.xpath('//div[@class="article block untagged mb15 typs_hot"]')
for url_info in url_infos:
id=url_info.xpath('div[1]/a[2]/h2/text()')[0]#通过xpath定位用户名的位置
print(id)
代码思路:
批量爬取的时候,先抓大后抓小,寻找循环点(折叠元素,找到段子完整的信息标签),然后在id完整xpath中删除循环部分,即可以循环的到id
相同字符开头的多个标签:不需要构造多个Xpath,通过starts-with()便可以获取多个标签内容
from lxml import etree
html1='''
<li class="tag-1">需要的内容1</li>
<li class="tag-2">需要的内容2</li>
<li class="tag-3">需要的内容3</li>
'''
selector=etree.HTML(html1)
contents=selector.xpath('//li[starts-with(@class,"tag")]/text()')#要获取的内容的相同之处:属性class以tag开始starts-with的li标签的text
for content in contents:
print(content)
#------打印结果----
需要的内容1
需要的内容2
需要的内容3
标签嵌套:可以通过string(.)完成
from lxml import etree
html2='''
<div class="red">需要的内容1
<h1>需要的内容2</h1>
</div>
'''
selector=etree.HTML(html2)
content1=selector.xpath('//div[@class="red"]')[0]
content2=content1.xpath('string(.)')
print(content2)#注意content2就包含了内容1和内容2
#------打印结果----
需要的内容1
需要的内容2
5.2.4 性能对比(lxml—BeautifulSoup—re)
性能对比项目:糗事百科内容(用户ID,文字信息,好笑数量,评论数量)数据只返回不存储
代码分析:
1.导入对应的库
2.User-Agent
3.构造所有URL
4.定义三种爬虫方法函数
5.程序主入口,通过循环依次调用3种函数,记录开始时间,循环爬取数据,记录结束时间,最后打印出所需时间
爬取方法 | 性能 | 使用难度 | 安装难度 | 使用场景 |
---|---|---|---|---|
re | 快 | 困难 | 简单(内置模块) | 网页结构简单&想要避免额外依赖 |
BeautifulSoup | 慢 | 简单 | 简单 | 爬取数据较少,较慢不影响 |
Lxml | 快 | 简单 | 相对困难 | 数据大,追求效益时 |
API
返回JSON或XML格式的数据,而不是HTML
代码分析:
1.requests用于请求网页,lxml和re用于解析爬去网页数据,Pymongo库用于对MongoDB数据库的操作,time降低频率
2.创建MongoDB数据库的集合
3.User-Agent伪装
4.详细页链接的函数,Xpath语法来提取标签中的href信息,最后调用获取爬虫信息get_music_info()函数
5.获取音乐信息的函数,通过Xpath
6.
第八章:多进程爬虫
同一时刻cpu只执行一个进程,不同进程间快速切换,同时运行的感觉。每个线程执行程序的不同部分。
multiprocessing
from multiprocessing import Pool
pool=Pool(processes=4)#创建进程池,设置进程个数
pool.map(func,iterable[,chunksize])#iterable迭代参数例如url