学习笔记"/>
【极客学院】-python学习笔记
极客学院课程地址:.html?ss=1
向网页提交数据:
get,post 交互方式
分析目标网站
表单提交功能
get:从服务器获得数据
post:向服务器传数据
eg:
request.post
步骤:构造表单,提交,获取返回信息
异步加载:菜做好一道上一道
不同于 菜做好了,再一次性上齐
网页 → 审查 → Headers → Request Method:GET (页面并没有 more,这里也没有POST)
Form Data → page:2
当有多个 page 的时候,直接提取,可能因为异步加载,无法提取到 more 的信息
这时 可以建立一个字典,并用 request.post 去提交表单,提取数据
#-*-coding:utf8-*-
import requests
import reurl='/'data = {'entities_only':'true'<span style="background-color: rgb(153, 255, 153);">,</span>'page':'1'
}html_post = requests.post(url<span style="background-color: rgb(153, 255, 153);">,</span>data=data)
title = re.findall('"card-title">(.*?)</div>', html_post.text, re.S)for each in title:print (each)
继续
实战:
/
前20页的 课程名称,课程介绍,课程时间,课程等级,学习人数
步骤:
requests获取网页
re.sub换页
正则表达式匹配内容
问题:
课程介绍,后面是省略号 的情况该怎么办?
爬虫只能爬到可以看到的
有的课程的课程介绍也可能为空
解决方案:
先抓大后抓小:
另:windows下将命令提示符的编码强制转化成utf-8
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
实践中遇到问题:
按课程中的代码敲出来后,会有一些错误
比如运行后,info.txt 中没有内容:
因为:网页的元素不是课程里的那样了,所以需要修改匹配的线索,这样修改了 everyclass,title 和 content,
<li id="2430" test="0" deg="0" >
但是到 timeandlevel 又有错误了
TypeError: '_sre.SRE_Match' object is not subscriptable
说明:
“XXX”object is not subscriptable
说的是XXX对象不是可索引的,可索引的对象有list,tuple等
如果你确定你的XXX是一个可迭代对象的话,可以尝试用list()函数把它转化为列表,然后通过索引读取元素
尝试分部找规律,提出 time 和 level,
info['classtime'] = re.search('"time-icon"></i><em>(.*?)</em>',eachclass,re.S).group(1)
info['classlevel'] = re.search('"xinhao-<span style="color:#ff0000;">icon</span>"></i><em>(.*?)</em>',eachclass,re.S).group(1)
但是 有的 level 的 icon 后面可能会加数字,导致,查找出的结果会有none
<i class="xinhao-icon2"></i><em>中级</em>
后来发现问题在于,把 re.findall 写成了 re.search
timeandlevel = re.search('<em>(.*?)</em>',eachclass,re.S)
所以,只查找了一个 em,没办法分配哦
<_sre.SRE_Match object; span=(1122, 1146), match='<em>3课时\n\t\t\t\t\t\t\t57分钟</em>'>
<dd class="mar-b8"><i class="time-icon"></i><em>4课时
<span style="white-space:pre"> </span>56分钟</em>
</dd>
<dd class="zhongji"><span style="white-space:pre"> </span><i class="xinhao-icon"></i><em>初级</em>
</dd>
最终代码:
#-*-coding:utf8-*-import requests
import re#url = '/'#html = requests.get(url)#print(html.text)#content = re.findall('', html.text, re.S)class spider(object):def __init__(self):print (u'开始爬取内容...')def changepage(self,url,total_page):page_group = [] #获得需要爬取的所有 page 的列表now_page = int(re.search('pageNum=(\d+)', url, re.S).group(1))for i in range(now_page,total_page+1):link = re.sub('pageNum=\d+','pageNum=%s'%i,url, re.S)page_group.append(link)return page_groupdef getsource(self,url):html = requests.get(url) #获取网页源代码return html.textdef geteveryclass(self,source):#everyclass = re.findall('(<li deg="".*?</li>)',source,re.S ) #先把所有课程找出来everyclass = re.findall('(<li id=.*?</li>)',source,re.S )return everyclassdef getinfo(self,eachclass):info = {} #定义字典# info['title'] = re.search('target="_blank">(.*?)</a>',eachclass,re.S).group(1)info['title'] = re.search('title="(.*?)" alt',eachclass,re.S).group(1)# info['content'] = re.search('</h2><p>(.*?)</p>',eachclass,re.S).group(1)info['content'] = re.search('none;">(.*?)</p>',eachclass,re.S).group(1)#timeandlevel = re.search('<em>(.*?)</em>',eachclass,re.S)timeandlevel = re.<span style="background-color: rgb(153, 255, 153);">findall</span>('<em>(.*?)</em>',eachclass,re.S)info['classtime'] = timeandlevel[0]info['classlevel'] = timeandlevel[1]# info['classtime'] = re.search('"time-icon"></i><em>(.*?)</em>',eachclass,re.S).group(1)# info['classlevel'] = re.search('"xinhao-icon"></i><em>(.*?)</em>',eachclass,re.S).group(1)info['learnnum'] = re.search('"learn-number">(.*?)</em>',eachclass,re.S).group(1)return infodef saveinfo(self,classinfo):f = open('info.txt','a') #打开 info.txt, 使用追加的方式for each in classinfo:f.writelines('title:' + each['title'] + '\n')f.writelines('content:' + each['content'] + '\n')f.writelines('classtime:' + each['classtime'] + '\n')f.writelines('classlevel:' + each['classlevel'] + '\n')f.writelines('learnnum:' + each['learnnum'] + '\n\n')f.close()#程序入口if __name__ == '__main__': #如果程序是自己使用 .py 文件运行classinfo = [] #定义一个列表用来存课程信息url = '/?pageNum=1'jikespider = spider() #实例化 类all_links = jikespider.changepage(url,2)for link in all_links:print(u'正在处理页面: '+ link)html = jikespider.getsource(link)everyclass = jikespider.geteveryclass(html)for each in everyclass:info = jikespider.getinfo(each)classinfo.append(info)jikespider.saveinfo(classinfo)
知识点:
参考:
Python中re(正则表达式)模块学习 .html
[1]re.search
re.search函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回,如果字符串没有匹配,则返回None。
re.search的函数原型为: re.search(pattern, string, flags)
每个参数的含意与re.match一样。
re.match与re.search的区别:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
now_page = int(re.search('pageNum=(\d+)', url, re.S).group(1))
python group()
参考:.html
正则表达式中,group()用来提出分组截获的字符串,()用来分组
例:
import re
a = "123abc456"
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0) #123abc456,返回整体
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1) #123
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2) #abc
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3) #456
re.search('pageNum=(\d+)', url, re.S) <span style="white-space:pre"> </span>#<_sre.SRE_Match object; span=(35, 44), match='pageNum=1'>
re.search('pageNum=(\d+)', url, re.S).group(1)<span style="white-space:pre"> </span># 1
re.match
re.match 尝试从字符串的开始匹配一个模式,如:下面的例子匹配第一个单词。
re.match的函数原型为:re.match(pattern, string, flags)
第一个参数是正则表达式,这里为"(\w+)\s",如果匹配成功,则返回一个Match,否则返回一个None;
第二个参数表示要匹配的字符串;
第三个参数是标致位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
[2]re.sub
re.sub用于替换字符串中的匹配项。下面一个例子将字符串中的空格 ' ' 替换成 '-' :
re.sub的函数原型为:re.sub(pattern, repl, string, count)
其中第二个参数是替换后的字符串;本例中为'-'
第四个参数指替换个数。默认为0,表示每个匹配项都替换。
re.sub还允许使用函数对匹配项的替换进行复杂的处理。如:re.sub(r'\s', lambda m: '[' + m.group(0) + ']', text, 0);将字符串中的空格' '替换为'[ ]'。
for i in range(1,3):link = re.sub('pageNum=\d+','pageNum=%s'%i,url, re.S)print(link)
结果:
/?pageNum=1
/?pageNum=2
[3]re.findall
re.findall可以获取字符串中所有匹配的字符串。如:re.findall(r'\w*oo\w*', text);获取字符串中,包含'oo'的所有单词。
everyclass = re.findall('(<li id=.*?</li>)',source,re.S)
timeandlevel = re.findall('<em>(.*?)</em>',eachclass,re.S)
info['classtime'] = timeandlevel[0]
info['classlevel'] = timeandlevel[1]
更多推荐
【极客学院】-python学习笔记
发布评论