日期:2020.01.22

博客期:130

星期三

  【代码说明,如果要使用此页代码,必须在本博客页面评论区给予说明】

  //博客总体说明

  1、准备工作(本期博客)

  2、爬取工作

  3、数据处理

  4、信息展示

  今天来说一说爬取的工作进展,我们的要求是爬取首都之窗的信件类型,那么我们就开始吧!

  首先,先找到网页:http://www.beijing.gov.cn/hudong/hdjl/com.web.search.mailList.flow

  然后找到网页的结构,发现是简单的HTML结构,那我们就可以启动Scrapy框架了。

  前边说了,之前是一直报403 Forbidden的错,原因我已经找到了!因为广大运营网站不可能希望各个程序员都能够轻易爬走自己的数据,那么怎么办呢?诶~他就对每个请求访问的用户进行检查,发现有一类用户什么都没有,就是想访问,网站一看到这种用户心里可真不是滋味,就会断定“你是来爬我的数据的”,你自然就被网站服务器禁掉了!人家有了“政策”,我们程序员就要想对策是吧!诶,我们可以在爬取的时候,模拟添加一个header,让服务器误认为我们是人,我们应该得到数据!

  

  进行改造:(这是截图没有错,到时候我会给你们代码的)

  

  嗯,现在服务器终于肯乖乖听话了!

  先来看我们的基础数据类型:

  

  由此我们可以构造基础的 Bean 类型了(为了方便引入,我就使用Bean当作类名了)

   看代码: 

 # [ 保存的数据格式 ]
class Bean: # 构造方法
def __init__(self,asker,responser,askTime,responseTime,title,questionSupport,responseSupport,responseUnsupport,questionText,responseText):
self.asker = asker
self.responser = responser
self.askTime = askTime
self.responseTime = responseTime
self.title = title
self.questionSupport = questionSupport
self.responseSupport = responseSupport
self.responseUnsupport = responseUnsupport
self.questionText = questionText
self.responseText = responseText # 在控制台输出结果(测试用)
def display(self):
print("提问方:"+self.asker)
print("回答方:"+self.responser)
print("提问时间:" + self.askTime)
print("回答时间:" + self.responseTime)
print("问题标题:" + self.title)
print("问题支持量:" + self.questionSupport)
print("回答点赞数:" + self.responseSupport)
print("回答被踩数:" + self.responseUnsupport)
print("提问具体内容:" + self.questionText)
print("回答具体内容:" + self.responseText) def toString(self):
strs = ""
strs = strs + self.asker;
strs = strs + "\t"
strs = strs + self.responser;
strs = strs + "\t"
strs = strs + self.askTime;
strs = strs + "\t"
strs = strs + self.responseTime;
strs = strs + "\t"
strs = strs + self.title;
strs = strs + self.questionSupport;
strs = strs + "\t"
strs = strs + self.responseSupport;
strs = strs + "\t"
strs = strs + self.responseUnsupport;
strs = strs + "\t"
strs = strs + self.questionText;
strs = strs + "\t"
strs = strs + self.responseText;
return strs # 将信息附加到文件里
def addToFile(self,fpath, model):
f = codecs.open(fpath, model, 'utf-8')
f.write(self.toString()+"\n")
f.close() # --------------------[基础数据]
# 提问方
asker = ""
# 回答方
responser = ""
# 提问时间
askTime = ""
# 回答时间
responseTime = ""
# 问题标题
title = ""
# 问题支持量
questionSupport = ""
# 回答点赞数
responseSupport = ""
# 回答被踩数
responseUnsupport = ""
# 问题具体内容
questionText = ""
# 回答具体内容
responseText = ""

Bean.py

  //-------[代码解析]

  这算是一个中介者,沟通着数据与展示或者数据与文件,这个类相当于是对数据的处理的方法封装

  ... ...

  忘了展示字符串的标签处理封装类了:

 # [ 对字符串的特殊处理方法-集合 ]
class StrSpecialDealer:
@staticmethod
def getReaction(stri):
strs = str(stri).replace(" ","")
strs = strs[strs.find('>')+1:strs.rfind('<')]
strs = strs.replace("\t","")
strs = strs.replace("\r","")
strs = strs.replace("\n","")
return strs

StrSpecialDealer.py

  嗯,之后我们需要想如何根据网页地址来获取html

  比如给定了原网站当中的其中一条比如对应网页:

  需要我们制作一个对应的网站爬取结点类(它的任务是对于已经给定的网页,进行爬取,并封装成我们上述的Bean类型)

  看代码:(省略导包...)

 # [ 信息爬取结点 ]
class DetailConnector:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36'}
basicURL = "" # ---[定义构造方法]
def __init__(self, url):
self.basicURL = url # 获取 url 的内部 HTML 代码
def getHTMLText(self):
req = request.Request(url=self.basicURL, headers=self.headers)
r = request.urlopen(req).read().decode()
return r # 获取基本数据
def getBean(self):
index_html = self.getHTMLText()
index_sel = parsel.Selector(index_html)
container_div = index_sel.css('div .container')[0]
container_strong = index_sel.css('div strong')[0]
container_retire = index_sel.css('div div div div')[5] #基础数据配置
title = " "
num_supp = " "
question_toBuilder = " "
question_time = " "
support_quert = " "
quText = " "
answer_name = " "
answer_time = " "
answer_text = " "
num_supp = " "
num_unsupp = " " #------------------------------------------------------------------------------------------提问内容
# 获取提问标题
title = str(container_strong.extract())
title = title.replace("<strong>", "")
title = title.replace("</strong>", "") # 获取来信人
container_builder = container_retire.css("div div")
question_toBuilder = str(container_builder.extract()[0])
question_toBuilder = StrSpecialDealer.getReaction(question_toBuilder)
if (question_toBuilder.__contains__("来信人:")):
question_toBuilder = question_toBuilder.replace("来信人:", "") # 获取提问时间
question_time = str(container_builder.extract()[1])
question_time = StrSpecialDealer.getReaction(question_time)
if (question_time.__contains__("时间:")):
question_time = question_time.replace("时间:", "") # 获取网友支持量
support_quert = str(container_builder.extract()[2])
support_quert = support_quert[support_quert.find('>') + 1:support_quert.rfind('<')]
support_quert = StrSpecialDealer.getReaction(support_quert) # 获取问题具体内容
quText = str(index_sel.css('div div div div').extract()[9])
if(quText.__contains__("input")):
quText = str(index_sel.css('div div div div').extract()[10])
quText = quText.replace("<p>", "")
quText = quText.replace("</p>", "")
quText = StrSpecialDealer.getReaction(quText) # ------------------------------------------------------------------------------------------回答内容
try:
# 回答点赞数
num_supp = str(index_sel.css('div a span').extract()[0])
num_supp = StrSpecialDealer.getReaction(num_supp)
# 回答不支持数
num_unsupp = str(index_sel.css('div a span').extract()[1])
num_unsupp = StrSpecialDealer.getReaction(num_unsupp)
# 获取回答方
answer_name = str(container_div.css("div div div div div div div").extract()[1])
answer_name = answer_name.replace("<strong>", "")
answer_name = answer_name.replace("</strong>", "")
answer_name = answer_name.replace("</div>", "")
answer_name = answer_name.replace(" ", "")
answer_name = answer_name.replace("\t", "")
answer_name = answer_name.replace("\r", "")
answer_name = answer_name.replace("\n", "")
answer_name = answer_name[answer_name.find('>') + 1:answer_name.__len__()]
# ---------------------不想带着这个符号就拿开
if (answer_name.__contains__("[官方回答]:")):
answer_name = answer_name.replace("[官方回答]:", "")
# 答复时间
answer_time = str(index_sel.css('div div div div div div div div')[2].extract())
answer_time = StrSpecialDealer.getReaction(answer_time)
if (answer_time.__contains__("答复时间:")):
answer_time = answer_time.replace("答复时间:", "")
# 答复具体内容
answer_text = str(index_sel.css('div div div div div div div')[4].extract())
answer_text = StrSpecialDealer.getReaction(answer_text)
answer_text = answer_text.replace("<p>", "")
answer_text = answer_text.replace("</p>", "")
except:
pass bean = Bean(question_toBuilder, answer_name, question_time, answer_time, title, support_quert, num_supp,
num_unsupp, quText, answer_text) return bean

DetailConnector.py

  此代码对应测试代码

dc = DetailConnector("http://www.beijing.gov.cn/hudong/hdjl/com.web.consult.consultDetail.flow?originalId=AH20012200024")
dc.getBean().display()

  测试结果:

   里面用到了CSS选择器的使用

   CSS选择器的使用方法(参考网页):https://www.w3school.com.cn/cssref/css_selectors.ASP

   但是有了这一部分还是不行,我们需要从原网站找到对应网站的链接地址!

   而且从第123期博客,我们可以知道:对应链接的onclick事件的两个参数分别对应的跳转地址关系,所以我们看:

 # [ 网页爬取的直接对象 ]
class WebConnector: basicURL = "http://www.beijing.gov.cn/hudong/hdjl/com.web.search.mailList.flow"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36'} # ---[定义构造方法]
def __init__(self):
pass # 获取 url 的内部 HTML 代码
def getHTMLText(self):
req = request.Request(url=self.basicURL, headers=self.headers)
r = request.urlopen(req).read().decode()
return r # 获取页面内的基本链接
def getFirstChanel(self):
index_html = self.getHTMLText()
index_sel = parsel.Selector(index_html)
links = index_sel.css('div #mailul').css("a[onclick]").extract()
inNum = links.__len__()
for seat in range(0, inNum):
# 获取相应的<a>标签
pe = links[seat]
# 找到第一个 < 字符的位置
seat_turol = str(pe).find('>')
# 找到第一个 " 字符的位置
seat_stnvs = str(pe).find('"')
# 去掉空格
pe = str(pe)[seat_stnvs:seat_turol].replace(" ","")
# 获取资源
pe = pe[14:pe.__len__()-2]
pe = pe.replace("'","")
# 整理成 需要关联数据的样式
mor = pe.split(",")
# ---[ 构造网址 ]
url_get_item = "";
# 对第一个数据的判断
if(mor[0]=="咨询"):
url_get_item = "http://www.beijing.gov.cn/hudong/hdjl/com.web.consult.consultDetail.flow?originalId="
else:
if(mor[0]=="建议"):
url_get_item = "http://www.beijing.gov.cn/hudong/hdjl/com.web.suggest.suggesDetail.flow?originalId="
url_get_item = url_get_item + mor[1] model = "a+" if(seat==0):
model = "w+" dc = DetailConnector(url_get_item)
dc.getBean().addToFile("../testFile/emails.txt",model)

WebConnector.py

   此代码对应测试代码:

wc = WebConnector()
wc.getFirstChanel()

    测试结果是将默认得到的第一页的内容爬取到文件email.txt里(分隔符为制表符 "\t" )

  

  但是这还是没有结束,因为这只有默认的6条数据,如何继续爬取剩下的5624-1页的数据呢?

  我目前找到了它传输数据的JSON包(附链接:http://www.beijing.gov.cn/hudong/hdjl/com.web.search.mailList.mailList.biz.ext

  截图如下:

  

  PS:前面那期博客内容应该是不全的,因为爬到第27页才出来一个特殊的页面:(居然还有投诉类型的?!!)

  

  投诉类型对应页面前缀为http://www.beijing.gov.cn/hudong/hdjl/com.web.complain.complainDetail.flow?originalId=

Python 爬取 北京市政府首都之窗信件列表-[Scrapy框架](2020年寒假小目标04)的更多相关文章

  1. Python 爬取 北京市政府首都之窗信件列表-[后续补充]

    日期:2020.01.23 博客期:131 星期四 [本博客的代码如若要使用,请在下方评论区留言,之后再用(就是跟我说一声)] //博客总体说明 1.准备工作 2.爬取工作(本期博客) 3.数据处理 ...

  2. Python 爬取 北京市政府首都之窗信件列表-[信息展示]

    日期:2020.01.25 博客期:133 星期六 [代码说明,如果要使用此页代码,必须在本博客页面评论区给予说明] //博客总体说明 1.准备工作 2.爬取工作 3.数据处理 4.信息展示(本期博客 ...

  3. Python 爬取 北京市政府首都之窗信件列表-[数据处理]

    日期:2020.01.24 博客期:132 星期五 [代码说明,如果要使用此页代码,必须在本博客页面评论区给予说明] //博客总体说明 1.准备工作 2.爬取工作 3.数据处理(本期博客) 4.信息展 ...

  4. Python 爬取 热词并进行分类数据分析-[简单准备] (2020年寒假小目标05)

    日期:2020.01.27 博客期:135 星期一 [本博客的代码如若要使用,请在下方评论区留言,之后再用(就是跟我说一声)] 所有相关跳转: a.[简单准备](本期博客) b.[云图制作+数据导入] ...

  5. Python 爬取的类封装【将来可能会改造,持续更新...】(2020年寒假小目标09)

    日期:2020.02.09 博客期:148 星期日 按照要求,我来制作 Python 对外爬取类的固定部分的封装,以后在用 Python 做爬取的时候,可以直接使用此类并定义一个新函数来处理CSS选择 ...

  6. Python 爬取 热词并进行分类数据分析-[解释修复+热词引用]

    日期:2020.02.02 博客期:141 星期日 [本博客的代码如若要使用,请在下方评论区留言,之后再用(就是跟我说一声)] 所有相关跳转: a.[简单准备] b.[云图制作+数据导入] c.[拓扑 ...

  7. python爬取北京政府信件信息01

    python爬取,找到目标地址,开始研究网页代码格式,于是就开始根据之前学的知识进行爬取,出师不利啊,一开始爬取就出现了个问题,这是之前是没有遇到过的,明明地址没问题,就是显示网页不存在,于是就在百度 ...

  8. Python爬取招聘信息,并且存储到MySQL数据库中

    前面一篇文章主要讲述,如何通过Python爬取招聘信息,且爬取的日期为前一天的,同时将爬取的内容保存到数据库中:这篇文章主要讲述如何将python文件压缩成exe可执行文件,供后面的操作. 这系列文章 ...

  9. Python 爬取所有51VOA网站的Learn a words文本及mp3音频

    Python 爬取所有51VOA网站的Learn a words文本及mp3音频 #!/usr/bin/env python # -*- coding: utf-8 -*- #Python 爬取所有5 ...

随机推荐

  1. IIS-反向代理配置&&插件安装

    参考:https://www.cnblogs.com/pengcc/p/4329207.html 网络上好多开场的文章就说了好多的原理之类的这里我们直接开始配置.不过也要简单说下win下配置反向代理只 ...

  2. MySQL主从复制(一主两从)

       主库开启bin-log二进制日志功能,并建立slave账号,并授权从库连接主库,从库通过change master得到主库的相关同步信息, 然后连接主库进行验证,主库产生的新数据会导入到bin- ...

  3. SpringBoot2.x整合Shiro出现cors跨域问题(踩坑记录)

    1. Springboot如何跨域? 最简单的方法是: 定义一个配置CorsConfig类即可(是不是简单且无耦合到令人发指) @Configuration public class CorsConf ...

  4. 【JavaScript】关于eval("("+result+")")的认识

    起因是做现项目时,参用很久之前一个项目的代码,少了一行eval("("+result+")"):控制台始终运行不出结果 大致意思是:eval方法是将json字符 ...

  5. Plastic Bottle Manufacturer: Plastic Bottle Packaging Material, Is It Degradable?

    For plastic bottle packaging, the current global market demand is still growing. However, for plasti ...

  6. GRE Over IPSec配置

    路由器GRE over IPSec站点到站点VPN         问题分析:对于前面的经典的IPSec VPN的配置来说,兼容性较好,适合于多厂商操作的时候,但是这种经典的配置方式不适合在复杂的网路 ...

  7. 02-14Android学习进度报告十四

    今天我学习了关于构建一个可复用的自定义BaseAdapter的知识. 首先将Entity设置成泛型 代码示例: public class MyAdapter<T> extends Base ...

  8. 【PAT甲级】1053 Path of Equal Weight (30 分)(DFS)

    题意: 输入三个正整数N,M,S(N<=100,M<N,S<=2^30)分别代表数的结点个数,非叶子结点个数和需要查询的值,接下来输入N个正整数(<1000)代表每个结点的权重 ...

  9. Web性能测试工具推荐

    WEB性能测试工具主要分为三种: 一种是测试页面资源加载速度的: 一种是测试页面加载完毕后页面呈现.JS操作速度的: 一种是总体上对页面进行评价分析. ~~~如果谁有更好的工具也请一起分享下   1. ...

  10. Java Web 前端资源文件的路径问题

    WEB-INF是Java Web应用的安全目录,在部署时用于存放class文件.项目用到的库(jar包).Java Web应用的配置文件web.xml. 浏览器不能访问此目录下的资源,比如在WEB-I ...