Python爬虫项目教程(微课版)-参考答案.docx
Python 爬虫项目教程(微课版)习题参考答案练习 11. Flask 是一个比较简单的 Python Web 开发框架,你知道 Python 还有哪些比较流行的Web 开发框架吗?说说它们的主要区别。答:企业级开发框架Django 高并发处理框架Tornado 快速建站的框架Flask底层自定义协议网络框架Twisted2. 使用 GET 方法提交数据与使用 POST 方法提交数据有什么不同?在 Flask 中如何获取提交的数据?答:Flask 获取 GET/POST 数据: flask.request.values.get(参数名称,默认值)3. 使用 Flask 编写一个 Web 程序,它接收如下代码提交的 user_name 与 user_pass<form name="frm" method="post" action="/login"><input type="text" name="user_name" ><input type="password" name="user_pass"><input type="submit" value="Login" ></form>数据。答:import flask app=flask.Flask("web")app.route("/") def index():s='''<form name="frm" method="post" action="/login"><input type="text" name="user_name" ><input type="password" name="user_pass"><input type="submit" value="Login" ></form>'''return sapp.route("/login",methods="GET","POST") def login():user_name=flask.request.values.get("user_name","") user_pass=flask.request.values.get("user_pass","") return user_name+","+user_passapp.debug=True app.run()4. 说出下面正则表达式匹配的字符串分别是什么。(1)r"w+s"(2)r"w+b"(3)r"d+-d+"(4)r"w+(w+.)+w+"(5)r"(b|cd)ef" 答: 省略5. 使用正则表达式匹配 HTML 代码中所有形如<img src="http:/ /文件名.jpg">的 JPG图像文件,找出一个网站中所有这样表示的 JPG 图像文件,并下载这些图像文件。答:import urllib.request import redef getHtml(url): html=""try:resp=urllib.request.urlopen(url) data=resp.read()try:html=data.decode().lower() except:html=data.decode("gbk").lower() except Exception as err:print(err) return htmldef parseHtml(html):32try:imgReg=r'<img.+srcs*=s*"http:/.+.jpg"s*>' srcReg=r'http:/.+.jpg'while True:m=re.search(imgReg,html) if m:s=htmlm.start():m.end() n=re.search(srcReg,s) src=sn.start():n.end() download(src) html=htmlm.end():else:breakexcept Exception as err: print(err)def download(src): try:print("downloding",src) resp=urllib.request.urlopen(src) data=resp.read() p=src.rfind("/")fn=srcp+1: fobj=open(fn,"wb") fobj.write(data) fobj.close() print("downloaded",fn)except Exception as err: print(err)url="."html=getHtml(url) parseHtml(html)练习 21. 简单说明Beautiful Soup 解析数据的特点。答: 省略2. 用Beautiful Soup 装载下面的 HTML 文档,并以规范的格式输出,比较与原来 HTML<body><div>Hi<br><span>Hello</SPAN><p><div>End</div>文档的区别,说明 Beautiful Soup 是如何修改的。答:from bs4 import BeautifulSouphtml='''<body><div>Hi<br><span>Hello</SPAN><p><div>End</div> '''soup=BeautifulSoup(html,"html.parser") print(soup.prettify()3. 重新编写本书项目 1 中爬取外汇网站数据的程序,使用Beautiful Soup 分解出<tr></tr>中的<td></td>数据。答:import urllib.requestfrom bs4 import BeautifulSoup import sqlite3class MySpider:def openDB(self):# 初始化数据库,创建数据库 rates.db 与一张空表 rates self.con = sqlite3.connect("rates.db") self.cursor = self.con.cursor()try:self.cursor.execute("drop table rates") except:passsql = "create table rates (Currency varchar(256) primary key,TSP float,CSP float, TBP float, CBP float,Time varchar(256)"try:self.cursor.execute(sql) except:passdef closeDB(self): # 关闭数据库mit() self.con.close()def insertDB(self, Currency, TSP, CSP, TBP, CBP, Time): # 记录插入数据库try:sql = "insert into rates (Currency,TSP,CSP,TBP,CBP,Time) values (?,?,?,?,?,?)"self.cursor.execute(sql, Currency, TSP, CSP, TBP, CBP,Time)except Exception as err: print(err)def show(self): # 显示函数self.cursor.execute("select Currency,TSP,CSP,TBP,CBP,Time fromrates")rows = self.cursor.fetchall()print("%-18s%-12s%-12s%-12s%-12s%-12s" % ("Currency", "TSP","CSP", "TBP", "CBP", "Time")for row in rows:print("%-18s%-12.2f%-12.2f%-12.2f%-12.2f%-12s" % (row0,row1, row2, row3, row4, row5)def spider(self, url): # 爬虫函数try:resp = urllib.request.urlopen(url) data = resp.read()html = data.decode() soup=BeautifulSoup(html,"html.parser") div=soup.find("div",attrs="id":"realRateInfo")trs=div.find_all("tr") for tr in trs1:tds=tr.find_all("td") Currency = tds0.text.strip() TSP = float(tds3.text)CSP = float(tds4.text) TBP = float(tds5.text) CBP = float(tds6.text) Time = tds7.text.strip()self.insertDB(Currency, TSP, CSP, TBP, CBP, Time) except Exception as err:print(err)def process(self): # 爬取过程self.openDB()self.spider(" self.show()self.closeDB()# 主程序spider = MySpider() spider.process()<body><bookstore><book id="b1"><title lang="english">Harry Potter</title><price>23.99</price></book><book id="b2"><title lang="chinese">学习 XML</title><price>39.95</price></book><book id="b3"><title lang="english">Learning Python</title><price>30.20</price></book></bookstore></body></html>4. 下面是一段 HTML 代码:试用 Beautiful Soup 完成下面的任务。(1) 找出所有书的名称。(2) 找出所有英文书的名称与价格。(3) 找出价格在 30 元以上的所有书的名称。答:from bs4 import BeautifulSouphtml='''<body><bookstore><book id="b1"><title lang="english">Harry Potter</title><price>23.99</price></book><book id="b2"><title lang="chinese">学习 XML</title><price>39.95</price></book><book id="b3"><title lang="english">Learning Python</title><price>30.20</price></book></bookstore></body></html> '''soup=BeautifulSoup(html,"html.parser") books=soup.find_all("book")for b in books: print(b.find("title").text)print() books=soup.find_all("book") for b in books:title=b.find("title",attrs="lang":"english") if title:print(title.text)print()for b in books: price=b.find("price").text if float(price)<30:print(b.find("title").text)5. 编写一个爬取 Python 最新版本的 Windows 64 位压缩包的程序,程序分两个部分。(1) 访问 Python 下载页面“https:/www.python.org/downloads/”,如图 2-8-1 所示。图 2-8-1 Python 下载页面from bs4 import Beautiful Soup import urllib.requestdef searchPython(url): resp=urllib.request.urlopen(url) data=resp.read() html=data.decode() soup=Beautiful Soup(html,"lxml")ol=soup.find(name="ol",attrs="class":"list-row-container menu") lis=ol.find_all("li")for li in lis:a=li.find(name="span",attrs="class":"release-number").find("a")python=a.text url=a"href"print("%-20s %s" %(python,url)try:searchPython("https:/www.python.org/downloads/") except Exception as e:print(e)分析 HTML 代码结构,编写下面的程序,爬取所有发行的 Python 版本与下载地址。执行该程序,部分结果如下:Python2.5.4/download/releases/2.5.4/Python2.4.6/download/releases/2.4.6/Python2.5.3/download/releases/2.5.3/Python2.6.1/download/releases/2.6.1/Python3.0.0/download/releases/3.0/(2) 在这个程序的基础上进一步编写程序,找出最新的版本,自动进入最新版本下载页面,找出这个版本的 Windows 64 位的 ZIP 压缩包的下载地址,并自动下载这个 Python 压缩包。答:from bs4 importBeautifulSoupimport urllib.request import redef getLatestVersion(pList): python=""mVersion="" url=""for p in pList: m=re.search(r"(d+).(d+).(d+)",p"python") group=m.groups()s=""for g in group: s=s+("%03d"%int(g)if s>mVersion: python=p"python" url=p"url" mVersion=sreturn python,urldef searchPython(surl): resp=urllib.request.urlopen(surl) data=resp.read() html=data.decode() soup=BeautifulSoup(html,"lxml")div=soup.find("div",attrs="class":"row download-list-widget") ol=div.find(name="ol",attrs="class":"list-row-container menu") lis=ol.find_all("li")pList=for li in lis: a=li.find(name="span",attrs="class":"release-number").find("a")python=a.text url=urllib.request.urljoin(surl,a"href") print("%-20s %s" %(python,url) pList.append("python":python,"url":url)return pListtry:pList=searchPython("https:/www.python.org/downloads/") python,url=getLatestVersion(pList)print("The latest version") print(python,url)except Exception as e: print(e)6. 在中国天气网中查找一个城市,如深圳,会转到地址为“ weather/101280601.shtml”的网页显示深圳的天气预报,如图 2-8-2 所示。图 2-8-2 深圳的天气预报from bs4 import BeautifulSoup from bs4 import UnicodeDammit import urllib.requesturl=" try:headers="User-Agent":"Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"req=urllib.request.Request(url,headers=headers) data=urllib.request.urlopen(req) data=data.read() dammit=UnicodeDammit(data,"utf-8","gbk") data=dammit.unicode_markup soup=BeautifulSoup(data,"lxml") lis=soup.select("ulclass='t clearfix' li") for li in lis:try:date=li.select('h1')0.text weather=li.select('pclass="wea"')0.text编写爬虫程序爬取该网站 7 天内的天气预报,包括日期、天气、温度等数据。答:temp=li.select('pclass="tem" span')0.text+"/"+li.select('pclass="tem" i')0.textprint(date,weather,temp) except Exception as err:print(err) except Exception as err:print(err)练习 31. 什么是深度优先法和广度优先法,它们有什么特点? 答:省略2. 如何启动一个 Python 线程?为什么说爬虫程序一般都会使用多线程? 答:省略3. 设计两个网页 A.html 与 B.html,它们都包含相同结构的学生信息(姓名、性别、年龄)。A.html 文件与 B.html 文件如下。<div>姓名: A1</div><div>性别: 男</div><div>年龄: 20</div><div>姓名: A10</div><div>性别: 女</div><div>年龄: 18</div>(1)A.html:(2)B.html:<div>姓名: B1</div><div>性别: 男</div><div>年龄: 20</div><div>姓名: B10</div><div>性别: 女</div><div>年龄: 18</div>设计一个包含两个线程的爬虫程序,一个线程爬取 A.html,另外一个线程爬取 B.html,爬取的学生信息都保存到列表 students 中,最后显示爬取的结果。答:(1) server.pyimport flaskapp=flask.Flask("web") app.route("/A")def A():s='''<div>姓名: A1</div><div>性别: 男</div><div>年龄: 20</div><div>姓名: A10</div><div>性别: 女</div><div>年龄: 18</div> '''return sapp.route("/B") def B():s='''<div>姓名: B1</div><div>性别: 男</div><div>年龄: 20</div><div>姓名: B10</div><div>性别: 女</div><div>年龄: 18</div> '''return sapp.debug=True app.run()(2) spider.pyfrom bs4 import BeautifulSoup import urllib.requestimport threadinglock=threading.RLock() def getValue(s):p=s.find(":") return sp+1:def getAB(page): global students try:resp=urllib.request.urlopen("http:/127.0.0.1:5000/"+page) html=resp.read().decode() soup=BeautifulSoup(html,"html.parser") divs=soup.find_all("div")i=0while i<len(divs): name=getValue(divsi.text) sex=getValue(divsi+1.text) age=getValue(divsi+2.text) i=i+3lock.acquire() students.append(name,sex,age) lock.release()except Exception as err: print(err)students= TA=threading.Thread(target=getAB,args="A") TB=threading.Thread(target=getAB,args="B") TA.start()TB.start() TA.join()TB.join()print(students)结果:' B1', ' 男', ' 20', ' B10', ' 女', ' 18', ' A1', ' 男', ' 20', ' A10', ' 女', ' 18'4. 设计一个爬虫程序,爬取一个网站的所有图像。答:from bs4 import BeautifulSoup from bs4 import UnicodeDammit import urllib.requestimport osdef imageSpider(start_url): try:urls= req=urllib.request.Request(start_url,headers=headers) data=urllib.request.urlopen(req)data=data.read() dammit=UnicodeDammit(data,"utf-8","gbk") data=dammit.unicode_markup soup=BeautifulSoup(data,"lxml") images=soup.select("img")for image in images: try:src=image"src" url=urllib.request.urljoin(start_url,src) if url not in urls:urls.append(url) print(url) download(url)except Exception as err: print(err)except Exception as err: print(err)def download(url): global count try:count=count+1 if(urllen(url)-4="."):ext=urllen(url)-4: else:ext="" req=urllib.request.Request(url,headers=headers) data=urllib.request.urlopen(req,timeout=100) data=data.read() fobj=open("images"+str(count)+ext,"wb") fobj.write(data)fobj.close()print("downloaded "+str(count)+ext) except Exception as err:print(err)headers = "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"count=0if not os.path.exists("images"): os.mkdir("images")start_url=" imageSpider(start_url)练习 41. 简单说明Scrapy 的入口地址的规定。答:省略2. 比较使用XPath 和 Beautiful Soup 解析 HTML 代码的特点与区别。答:省略3. 在 Scrapy 中如何把爬取的数据写入数据库?items.py 与 pipelines.py 文件有什么作用?答:items.py 定义数据字段,pipelines.py 获取数据进行存储。4. Python 中的 yield 语句如何工作?为什么 Scrapy 爬到的数据使用 yield 语句返回, 而不是使用 return 语句返回?答:省略5. Scrapy 是如何实现爬取多个网页的数据的?如何理解分布式爬取过程? 答:省略import flask app=flask.Flask( name ) app.route("/")def show():page = flask.request.args.get("page") if "page" in flask.request. args else "1"maxpage=3 page=int(page) st="<h3>学生信息表</h3>"st=st+"<table border='1' width='300'>"fobj=open("students"+str(page)+".txt","rt",encoding="utf-8") while True:#读取一行,去除行尾部“n”换行符号s=fobj.readline().strip("n") #如果读到文件尾部就退出if s="":6. 有一个服务器程序,它根据请求页面的不同来展示 3 组学生信息,这些学生信息分别存储在 students1.txt、students2.txt、students3.txt 文件中,每个页面有相同的结构(学号 No、姓名 Name、性别 Gender、年龄 Age),参数 page=N 控制展示 studentsN.txt 的学生表格(N=1,2,3),程序如下:break #按逗号拆分s=s.split(",")st=st+"<tr>"#把各个数据组织在<td></td>中for i in range(len(s):st=st+"<td>"+si+"</td>" #完成一行st=st+"</tr>"fobj.close() st=st+"</table>" st=st+"<div>"if page>1:st = st + "<a href='/?page=" +str(page-1) + "'>【前一页】</a>" if page<maxpage:st=st+"<a href='/?page="+str(page+1)+"'>【下一页】</a>" st=st+"</div>"st=st+"<input type='hidden' name='page' value='"+str(page)+"'>" st=st+"<div>Page: "+str(page)+"/"+str(maxpage)+"</div>"return stif name =" main ": app.run()执行服务器程序,学生信息如图 4-10-1 所示。图 4-10-1 学生信息使用 Scrapy 设计一个爬虫程序,爬取所有学生的信息并将其存储到数据库中。答:1、server.pyimport flask app=flask.Flask( name ) app.route("/")def show():page = flask.request.args.get("page") if "page" in flask.request.args else "1"maxpage=3 page=int(page)st="<h3>学生信息表</h3>"st=st+"<table border='1' width='300'>" fobj=open("students"+str(page)+".txt","rt",encoding="utf-8") while True:#读取一行,去除行尾部“n”换行符号s=fobj.readline().strip("n") #如果读到文件尾部就退出if s="":break #按逗号拆分s=s.split(",") st=st+"<tr>"#把各个数据组织在<td></td>中for i in range(len(s):st=st+"<td>"+si+"</td>" #完成一行st=st+"</tr>" fobj.close() st=st+"</table>" st=st+"<div>"if page>1:st = st + "<a href='/?page=" +str(page-1) + "'>【前一页】</a>" if page<maxpage:st=st+"<a href='/?page="+str(page+1)+"'>【下一页】</a>" st=st+"</div>"st=st+"<input type='hidden' name='page' value='"+str(page)+"'>" st=st+"<div>Page: "+str(page)+"/"+str(maxpage)+"</div>"return stif name =" main ": app.debug=True app.run()2、爬虫程序scrapy startproject demo(1) items.pyimport scrapyclass StudentItem(scrapy.Item):# define the fields for your item here like: No = scrapy.Field()Name=scrapy.Field() Gender=scrapy.Field() Age=scrapy.Field()(2) pipelines.pyimport sqlite3class DemoPipeline:def open_spider(self,spider): print("opened")try:self.con=sqlite3.connect("students.db") self.cursor=self.con.cursor()try:self.cursor.execute("drop table students") except:pass try:sql="""create table students(No varchar(8) primary key, Name varchar(32),Gender varchar(8), Age int)"""self.cursor.execute(sql) except:self.cursor.execute("delete from students") self.opened=Trueself.count=0except Exception as err: print(err) self.opened=Falsedef close_spider(self, spider): if self.opened:mit()self.con.close() self.opened=Falseprint("closed")print("总共爬取",self.count,"条记录")def process_item(self, item, spider): if self.opened: