前言

为了加入学校里面一个技术小组,我接受了写一个爬取学校网站通知公告的任务。这个任务比以前写的爬虫更难的地方在于,需要模拟登录才能获得页面,以及将得到的数据存入数据库。

本文按照日期来记录我完成任务的过程,然后再整理一遍全部代码。读者可以通过下方传送门去我个人博客阅读,这样通过侧栏目录跳转阅读。不介绍库的安装。

对爬取的网站地址等内容进行了一些“打码处理”。

个人博客传送门:

  • 爬虫学习笔记1一个简易爬虫
  • 爬虫学习笔记2模拟登录与数据库

转载声明

关于参考链接: 本文用到的其他博客的链接都以(我自己对内容的概括或者文章原标题-来源网站-作者名)的格式给出,关于作者名,只有博客作者自己明确声明为“原创”,我才会加上作者名。引用的文章内容我会放在来源链接的下方。

关于本文:我发一下链接都注明出处了,如果想转载,也请这样做。作者憧憬少,链接的话看浏览器地址栏。

任务介绍

爬取信息门户新闻并且存入数据库。

首先分解任务:

  1. 实现爬取综合新闻页面的公开新闻存入markdown文件中(190303完成)
  2. 将数据存到数据库(190304完成)
  3. 学习模拟登录(190305到190307完成)
  4. 爬取信息门户新闻(190308完成)
  5. (进阶)将代码进行封装、优化(目前未封装)
  6. (进阶)动态更新(目前未着手)

过程记录

190303 周日

练习爬取公开页面

我的第一个爬虫是在2月多的时候在家写的,那个只是个简单的爬虫,目标是公开的页面,不需要模拟登录,也不需要存储到数据库,直接存到txt文件中。

先爬取学校官网的综合新闻页面复习一下。

首先讲一下我的思路:

由于新闻和公告页面通常是有一个目录页面的,也就是包含子页面的链接,在目录的子页面内才是正文内容。

假设这一页目录有三个新闻,就像是下面:

  • 新闻目录

    • 新闻一
    • 新闻二
    • 新闻三
    • 点击查看下一页

这样的结构。

如果要写一个爬虫函数来爬取所有新闻页面,那么就要从目录着手。目录中含有前往别的新闻页面的链接,所以可以在目录页获取本页所有新闻的链接,遍历所有链接并提取新闻内容。

至于翻页也可以这样做到,“下一页”按钮也是一个链接,可以通过这个链接获取到下一页的内容。翻页部分原理比较简单,我是先攻克其他难关,把它留到最后写的。

提取单页面新闻

首先是提取单个页面的新闻。向目标url发出访问请求:

import requests
def getNews(url):'''提取页面的新闻与图片并存储为markdown文件:param url: 要爬取的目标网页url:return: 无'''#发送请求r=requests.get(url)#r为response对象html=r.text#r.text是请求的网页的内容print(html)
编码问题

这里遇到了第一个问题,提取到的页面有乱码。

解决方法:先获取响应对象的二进制响应内容,然后将其编码为utf8

参考链接:

  • python中response.text与response.content的区别-CSDN

requests.content返回的是二进制响应内容

而requests.text则是根据网页的响应来猜测编码

  • UNICODE,GBK,UTF-8区别(一个比较好的编码的教程,便于理解编码的概念)-博客园
  • Python解决抓取内容乱码问题(decode和encode解码)-CSDN-浅然_

字符串在Python内部的表示是unicode编码,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。

decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode(‘gb2312’),表示将gb2312编码的字符串str1转换成unicode编码。

encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode(‘utf-8’),表示将unicode编码的字符串str2转换成utf-8编码。

修改代码为:

#发送请求
r=requests.get(url)
html=r.content#获取二进制字节流
html=html.decode('utf-8')#转换为utf8编码(该网页使用的是utf8编码)
解析网页(bs4)

一开始我和之前一样使用正则表达式来提取,但是不够熟悉,总是写不出匹配的上的正则表达式。还是使用另一个东西——BeautifulSoup库

具体如何使用请查看其他教程,本文只说我自己用到的部分。

参考链接:

  • Python爬虫常用的几种数据提取方式-CSDN-凯里潇
  • 零基础入门python3爬虫-bilibili(里面的视频p11)
  • beautifulsoup(基本选择器,标准选择器,css选择器)-CSDN-Halosec_Wei(基本上是上面一个b站链接的文字版,不知道是不是同一个人)
  • beautifulsoup详细教程-脚本之家
  • beautifulsoup基本用法总结-CSDN-kikay

BeautifulSoup是Python的一个库,最主要的功能就是从网页爬取我们需要的数据。BeautifulSoup将html解析为对象进行处理,全部页面转变为字典或者数组,相对于正则表达式的方式,可以大大简化处理过程。

我目前的理解是,这个BeautifulSoup库需要用到其他html解析库,可以使用python自带的,也可以安装第三方库,其他的库就像功能扩展插件一样,没有的话它自己也能解析。我安装了名为lxml的解析库。

查看源代码,找到网页中有关新闻的代码,手动将其格式化之后如下(内容不重要,省略):

<h1 class="arti-title">标题省略</h1>
<p class="arti-metas"><span class="arti-update">发布时间:2019-01-23</span><span class="arti-update1">作者:xx</span><span class="arti-update2">来源:xxx</span>
</p><div class="entry"><article class="read"><div id="content"><div class='wp_articlecontent'><p>新闻前言省略</p><p><br /></p><p>新闻内容省略</p><p><img width="556" height="320" align="bottom" src="url省略" border="0"></p><p style="text-align:right;">(审稿:xx &nbsp;网络编辑:xx)</p></div></div></article>
</div>

接着上面的代码:

#解析html
soup=BeautifulSoup(html,"lxml")#返回已解析的对象#获取标题
title=soup.find('h1',class_='arti-title').string
#获取时间
update=soup.find('span',class_='arti-update').string
#获取正文标签
content=soup.find('div',class_='wp_articlecontent')
提取图片

我打算将新闻保存到markdown文件中,提取新闻中的图片的链接的地址,这样在md文件中就能显示出图片了。

#获取图片链接
base='学校官网url,用于和img标签中的相对地址拼接成绝对地址'
imgsTag=content.find_all('img')
imgsUrl=[]
for img in imgsTag:imgsUrl.append(base+img['src'])#拼接成完整的urlimg.extract()#删除图片标签
删除多余标签
#删除多余标签
for p in content.find_all('p',{'style':"text-align:center;"}):p.extract()
p=content.find('p', {'style': "text-align:right;"})
if(p!=None):p.extract()
保存到文件
# 拼接成字符串
#后来知道这样的提取方式其实不能完全提取到所有内容
fileContent=''
for i in content.contents:#遍历正文内容的所有子标签if(i.string!=None):#如果子标签里面有内容#print(i.string)#调试fileContent+=i.string#基本只剩下p标签了fileContent+='\n\n'#保存到md文件
with open('data.md','w') as fout:fout.write(fileContent)
代码总览
import requests
from bs4 import BeautifulSoup#第4个版本改名bs4而不是全名那么长了
def getNews(url):'''提取页面的新闻与图片并存储为markdown文件:param url: 要爬取的目标网页url:return: 无'''#发出请求r=requests.get(url)html=r.contenthtml=html.decode('utf-8')#转换编码#解析htmlsoup=BeautifulSoup(html,"lxml")content=soup.article#获取标题title=soup.find('h1',class_='arti-title').string#获取时间update=soup.find('span',class_='arti-update').string#获取正文content=soup.find('div',class_='wp_articlecontent')#获取图片链接base='http://xxxxx.xxx'#学校官网url,用于和img标签中的相对地址拼接成绝对地址imgsTag=content.find_all('img')imgsUrl=[]for img in imgsTag:imgsUrl.append(base+img['src'])#拼接成完整的urlimg.extract()#删除图片标签#删除多余标签for p in content.find_all('p',{'style':"text-align:center;"}):p.extract()p=content.find('p', {'style': "text-align:right;"})if(p!=None):p.extract()# 拼接成字符串fileContent=''for i in content.contents:if(i.string!=None):#print(i.string)#调试fileContent+=i.stringfileContent+='\n\n'with open('data.md','w') as fout:fout.write(fileContent)

提取多页面新闻

原理在上面说了,提取完单页基本上就完成了。

import requests
from bs4 import BeautifulSoup
def getNewsContents(url):'''爬取目录页面链接到的页面:param url: 新闻目录页面的url:return: 无'''#获取网页内容r=requests.get(url)#以get方式访问html=r.contenthtml=html.decode('utf-8')#获取每篇新闻的链接base='http://xxxxx.xxx'#学校官网url,用于和相对地址拼接成绝对地址soup=BeautifulSoup(html,'lxml')for page_url in soup.find_all('a',class_='column-news-item'):page_url=base+'/'+page_url['href']print(page_url)getNews(page_url)#调用提取单页函数

day1进度

  1. 实现爬取长安大学综合新闻页面的公开新闻存入markdown文件中
  2. 复习了requests库的使用
  3. 学习了BeautifulSoup4库的基本使用

190304 周一

这一天主要是将前一天爬取的数据存入数据库。

将数据存入数据库

安装MySQL数据库

参考链接:

  • 零基础入门python3爬虫-bilibili(里面的视频p4)

使用MySQL Workbench

MySQL Workbench是一个可视化工具,安装MySQL的时候自带(我安装的是最新版的),在安装目录找到它的exe然后加个快捷方式在桌面,可以方便地查看数据和执行SQL查询指令,具体使用方法可以问度娘。我现在也不是很会。

我创建的数据库名为news,里面创建了一个数据表chdnews。

连接数据库

和大多数数据库一样,MySQL是C/S模式的,也就是客户端(client)/服务端(server)模式的。数据库有可能在远程服务器上。想要使用数据库,就需要连接到数据库。

python中要使用数据库需要一个pymysql库。

下面是连接的代码:

import pymysql
#连接数据库
db = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root', db='news', charset='utf8')

这个连接函数看参数名就可以看出含义了。

  • host:主机ip,127.0.0.1是回传地址,指本机。也就是连接本电脑的MySQL的意思
  • port:端口号,用来和ip一起指定需要使用数据库的软件。在安装的时候会让你设置,默认3306
  • user&passwd:用户名和密码,在安装的时候已经设置好了
  • db:你要连接的数据库的名字。一台电脑上可以有很多数据库,数据库里面可以有很多数据表。
  • charset:字符编码

插入数据

接着可以准备一个游标,游标大概是一个用于存储结果集开头地址的指针吧,我是这么理解的。在我学了更多数据库知识后可能会更新这一部分。

#创建游标
cursor = db.cursor()

接着执行SQL的插入语句:

#插入
cursor.execute("insert into chdnews(`title`,`article`) values('{0}','{1}')".format(title,fileContent))#此处变量为上文代码中的变量

这里的SQL语句是这样的:

insert into 数据表名(字段名1,字段名2) values(值1,值2)

后面的format函数是python的格式化函数,将变量的值加入到字符串中对应位置。

最后提交:

#提交更改
db.commit()

接着打开workbench,就会发现已经存入数据库了。(你得把代码放在上面提取单页新闻的函数那里,放在保存到文件的那部分代码那儿)

day2进度

  1. 下载并安装MySQL以及MySQL Workbench
  2. 使用pymysql库进行数据库的连接,实现了把第一天得到的数据存入数据库

190305 周二

初步了解模拟登录

最后的任务需要爬取登录后才能查看的页面,于是我去搜索了很多博客,只放一部分对我有帮助的链接。

参考链接:

  • 模拟登录CSDN-博客园
  • 模拟登录github-博客园

首先查看一下需要的登录数据:

  1. 打开登录网页,用F12打开开发者工具,选择network(网络)选项卡
  2. 登录你的账号,此时控制台会显示一大堆请求与响应,找到以post方式发送的请求,一般排在第一个
  3. 那里会显示几个栏目,找到Form Data(表单数据),这个里面是你填写登录表单之后使用POST方式发送给服务端的内容。这里面除了自己填写的账号密码之外还有一些东西,比如下图的lt,dllt,execution,_eventId,rmShown这些都是在表单的隐藏域中,查看登录页面的源代码是可以看的到的。这些隐藏起来的东西是为了检验你是否是从浏览器进来的,只要获取到这些东西,再加上头部信息,就能伪装成浏览器了
  4. 至于头部信息,在下图也可以看到我折叠起来的几个栏目,有一个是Request Headers,这是我们在点击登录按钮时发送的POST请求信息的信息头。将里面的User-Agent给复制到你代码里面存在一个字典里面等会用
  5. 把头部信息和表单数据都看一下,准备一下

[外链图片转存失败(img-0xIVpQvD-1568113919185)(https://HaneChiri.github.io/blog_images/article/spider_f12_form_data.png)]

#登录前的准备
login_url = 'http://xxxx.xxx'#登录页面的url
#头部信息
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'#加上后面这些会后悔的,别加。'Host':'xx.xx.xx.xx','Referer':'http://xxx.xxx?xxx=http://xxx.xx','Origin':'http://xxx.xxx.xx'
}
#登录用的数据
login_data={'username': '你的账号','password': '你的密码','btn':'','lt': LT-790162-J9kW2aEFsK3ihu4AzXcovdsJy6cYBM1552123884047-D1Nx-cas,#实际上lt并不能这样写上去,下文会解释。这里记录我自己的错误'dllt': 'userNamePasswordLogin','execution': 'e1s1','_eventId': 'submit','rmShown': 1}

数据准备好之后就开始登录,使用的是requests的另一个方法——post。

向服务器发出请求(request)的方式有get和post,查看html源代码的时候在表单标签处可以看到表单提交的方法。如:

<form id="casLoginForm" method="post">

像这样写html代码会让浏览器在你按下登录按钮的时候以post的方式提交表单,也就是以post的方式向服务器发起request,将form data发送过去。

post方法的好处是在发送过程中会隐藏你的表单数据,不会被直接看到;

而前面使用过的get方法,会把你的表单数据加在url后面,网址后边以问号开头,以&连接的就是发送过去的参数。

涉及登录用post比较好,以免轻易泄露密码。

#以post方式发出登录请求
r=requests.post(login_url,headers=headers,data=login_data)

按理来说应该可以了呀,为什么不行?仍然得到登录页面。在这一天我折腾了很久,没有得到答案。

不过在找资料时却学到了其他的一些知识,关于cookie和session。

cookie和session

我目前的理解(如果不对欢迎留言):

http是无状态协议,两次访问都是独立的,不会保存状态信息。也就是你来过一次,下次再来的时候网站还是当你第一次来。那么怎么知道你来过,从而给你还原之前的数据呢?就有人想出cookie和session两种方式。

cookie(直译:小甜饼)是服务端(网站服务器)收到客户端(你电脑)的request(请求)的时候和response(响应)一起发给客户端的数据。客户端把它存在文件里面,并在下一次访问这个网站时将cookie随着request一起发送过去,这样服务端就会知道你就是之前来过的那个人了。cookie存储在客户端。

  1. 客户端发送request
  2. 服务端发送response附带一个cookie(一串数据)
  3. 客户端第二次访问时把cookie复制一份一起发过去
  4. 服务端看到你的cookie就知道你是谁了

session(会话)是在服务端内存中保存的一个数据结构,一旦有客户端来访问,那么就给这个客户端创建一个新的session在服务端的内存,并将它的session ID随着response发回给客户端。客户端第二次访问时,会将被分配的SID随着request一起发过来,服务端在这边验证SID之后就会知道你来过。session存储在服务端。

  1. 客户端发送request
  2. 服务端发送response并在自己这边创建一个session(一堆数据)并发送一个session ID给客户端
  3. 客户端第二次访问时把session ID一起发过去
  4. 服务端看到你的session ID就知道你是谁了

不过这俩是用来保持登录的,我还没登录成功想这个干啥?请看下一天。

day3进度

  1. 初步了解cookie和session的概念
  2. 了解如何使用chrome浏览器的控制台查看post表单信息
  3. 尝试使用requests的post方法模拟登录,失败,返回登录页面

190306 周三

表单校验码(非验证码)

怎么弄都不成功,都跳回登录页面。我只好去询问组长这是为什么。

原来我没发现表单校验码会变的!

一直没注意啊啊啊啊啊啊!

我没有认真比对过两次打开的乱码不一样,看结尾一样就以为一样了。其中的lt这个域每次打开网页都是不一样的,随机出的!

既然知道了问题,就好解决了。

#获取登录校验码
html=requests.post(login_url,headers=headers).text
soup=BeautifulSoup(html,'lxml')
lt=soup.find('input',{'name':'lt'})['value']
dllt=soup.find('input',{'name':'dllt'})['value']
execution = soup.find('input', {'name': 'execution'})['value']
_eventId = soup.find('input', {'name': '_eventId'})['value']
rmShown = soup.find('input', {'name': 'rmShown'})['value']
login_data={'username': input("请输入学号:"),'password': input("请输入密码:"),'btn':'','lt': lt,'dllt': dllt,'execution': execution,'_eventId': _eventId,'rmShown': rmShown
}

为了保险,我把其他的表单域也给解析赋值给变量了。

不过仍然无法登陆成功,而是进入了一个诡异的页面:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>

确实有进展,但是这是啥?nginx?查了一下是一个高性能的HTTP和反向代理服务器,但是和我现在登录有什么关系呢?(黑人问号.jpg)

利用session保持校验码

即使登录成功,还有一个问题无法解决,那就是我获取校验码的request和登录用的request是两次不同的访问请求呀,这样校验码又会变化。

我想起了前一天看到的session,这玩意不就能让服务端记住我?(cookie试了一下,保存下来的是空的文件不知道怎么回事)

于是新建一个会话:

#新建会话
session=requests.session()

在获取校验码的时候改成使用session变量来发起请求:

#获取登录校验码
html=session.post(login_url,headers=headers).text

这里的session是在客户端创建的,并不是服务端那个,我想它可能存储的是服务端发送过来的session ID吧。

同理在正式发送请求时这样:

#登录
r=session.post(login_url,headers=headers,data=login_data)

这样就能让服务端知道我是刚刚获取校验码的那个小伙汁:D

在这一天我没有办法验证是否有效,不过在之后我验证了这个方法的成功性。

day4进度

  1. 知道了原来有个每次会变化的校验码“lt”,找到了跳转回登录页面的原因。使用Beautifulsoup来获取每次的校验码,不过仍然没有解决无法登录的问题
  2. 使用session对象来保证获取校验码和登录时是同一个会话,未验证

190307 周四

多余的头部信息

我终于发现了问题所在!!!!!

headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',#'Host':'xxx.xxx.xxx.xxx',#'Referer':'http://xxx.xxx.xxx.xxx...',#不详细打码了#'Origin':'http://xxx.xxx.xxxx'#去掉多余的头信息才成功登录!!!!!卡了很久没想到是因为这个
}

头部信息写多了,我只保留了User-Agent之后成功登录了,你们能体会到我当时有多开心吗!

我将成为新世界的卡密小组里面最快完成的人!

解决了这个问题,剩下的就特别简单了。

当时我有一个下午的时间,于是我将进度迅速推进。

爬取通知公告

设登录页面为pageA,登录之后的页面跳转到pageB,而pageB有一个按钮跳转到pageC,这个pageC就是day1的时候的目录页面,里面有着pageC1、pageC2、pageC3……等页面的链接,而这个pageC最后面还有个按钮用于跳转到目录的下一页,也就是pageC?pageIndex=2,还有137页公告栏目录。

没有什么新的东西,和day1说的爬取方式差不多,只是页面正文的格式和day1的新闻不太一样。核心结构如下,我省略了很多:

<html><body><div class="bulletin-content" id="bulletin-contentpe65"><p style=";background: white"><a name="_GoBack"></a><span style="font-size: 20px;font-family: 仿宋">校属各单位:</span></p><p><br/></p></div></body>
</html>

大概就是一个<p>标签里面放一个或多个<span>标签,而这里面可能还会嵌套几个<span>标签,里面才有内容,而两个内部的<span>之间还可能有内容。

这要怎么解析?

在尝试了很多方案之后,我终于百度到一个函数:

tag.get_text()#提取名为tag的bs4标签的内部的所有文字

参考链接:

  • BeautifulSoup获取标签中包含的文字-CSDN-niewzh(正是这个博客解决了我的问题)
  • BeautifulSoup中的.text方法和get_text()方法的区别-CSDN

解决方案:

#获取正文内容
html=session.post(url,headers=headers).text
soup=BeautifulSoup(html,'lxml')article=soup.find('div',class_='bulletin-content')
news_content=''
for p in article.find_all('p'):if p.span!=None:#如果p含有一层spantext=str(p.get_text()).strip()#获取内容并去除多余空格news_content+=text+'\n'

接着我就把爬下来的东西存到数据库里面去了。弄完之后得去赶作业了,这一天的时间用完了。

day5进度

1.找到无法登录且跳转到未知页面的原因是头部信息加了多余的值,解决之后成功登录到信息门户,实现模拟登陆
2.利用之前爬取单个页面到文件的方法,用beautifulsoup解析并保存内容到文件
3.存入MySQL数据库中
4.还差爬取多页目录的功能,预计明天完成。整理代码后可提交

190308 周五

更多的目录页

开了一个新文件准备整理一下代码,并完成最后一个功能——爬取完目录页第一页之后爬取后面更多的页。

查看源代码的时候,找“第二页”这个按钮对应的链接,发现了规律:

<div class="pagination-info clearFix"><span title='共2740条记录 分137页显示'>2740/137</span><a href='detach.portal?pageIndex=1&amp;pageSize=&amp;.pmn=view&amp;.ia=false&amp;action=bulletinsMoreView&amp;search=true&amp;groupid=all&amp;.pen=pe65' title='点击跳转到第1页'>&lt;&lt;</a><div title="当前页">1</div>        <a href='detach.portal?pageIndex=2&amp;pageSize=&amp;.pmn=view&amp;.ia=false&amp;action=bulletinsMoreView&amp;search=true&amp;groupid=all&amp;.pen=pe65' title='点击跳转到第2页'>2</a>            <a href='detach.portal?pageIndex=3&amp;pageSize=&amp;.pmn=view&amp;.ia=false&amp;action=bulletinsMoreView&amp;search=true&amp;groupid=all&amp;.pen=pe65' title='点击跳转到第3页'>3</a><a href='detach.portal?pageIndex=4&amp;pageSize=&amp;.pmn=view&amp;.ia=false&amp;action=bulletinsMoreView&amp;search=true&amp;groupid=all&amp;.pen=pe65' title='点击跳转到第4页'>4</a><a href='detach.portal?pageIndex=5&amp;pageSize=&amp;.pmn=view&amp;.ia=false&amp;action=bulletinsMoreView&amp;search=true&amp;groupid=all&amp;.pen=pe65' title='点击跳转到第5页'>5</a><a href='detach.portal?pageIndex=6&amp;pageSize=&amp;.pmn=view&amp;.ia=false&amp;action=bulletinsMoreView&amp;search=true&amp;groupid=all&amp;.pen=pe65'>&gt;</a><a href='detach.portal?pageIndex=137&amp;pageSize=&amp;.pmn=view&amp;.ia=false&amp;action=bulletinsMoreView&amp;search=true&amp;groupid=all&amp;.pen=pe65' title='点击跳转到最后页'>&gt;&gt;</a>
</div>

可以看出,指向其他目录页的相对链接,只是参数略有不同,参数中只有pageIndex发生了变化。至于给url加参数,我记得前几天看到过。

#作为参数的字典
para={'pageIndex':1,#这里需要修改,先爬第一页'pageSize':'','.pmn':'view','.ia':'false','action':'bulletinsMoreView','search':'true','groupid':'all','.pen':'pe65'
}
catalogue_url='http://xxx.xx.xx.cn/detach.portal'#未加参数的新闻目录页urlsession = login()  # 获取已登录的session,这个自定义函数会在下面列出for i in range(1,page_count+1):#page_count是要获取的页数para['pageIndex']=i#设置新闻当前页的索引# 从目录页获取新闻页面链接html = session.post(catalogue_url,params=para).text

整理代码

要用到的库

import requests
import re
from bs4 import BeautifulSoup
import pymysql

get_bulletin

def get_bulletin(page_count):'''目录有多页,从第一页开始获取,往后获取page_count页的目录,并读取目录指向的所有公告:param page_count: 要爬取的目录页面的数量:return: 无'''para={'pageIndex':1,'pageSize':'','.pmn':'view','.ia':'false','action':'bulletinsMoreView','search':'true','groupid':'all','.pen':'pe65'}catalogue_url='http://xxx.xxx.xxx.cn/detach.portal'#未加参数的公告目录页urlsession = login()  # 获取已登录的sessionfor i in range(1,page_count+1):para['pageIndex']=i#设置公告当前页的索引# 从目录页获取公告页面链接html = session.post(catalogue_url,params=para).textsoup = BeautifulSoup(html, 'lxml')rss_title = soup.find_all('a', class_='rss-title')#将得到的链接与标题组装成字典bulletin_dict = {}for url in rss_title:bulletin_title = str(url.span.string).strip()bulletin_url = 'http://xxx.xx.xx.cn/' + url['href']bulletin_dict.setdefault(bulletin_title, bulletin_url)#添加一条公告记录#保存公告到数据库for bulletin_title, bulletin_url in bulletin_dict.items():#saveInTXT(bulletin_url, session, bulletin_title)#这个是保存到txt文件的函数,用于测试saveInDB(news_url, session, news_title)

login

def login():"""登录并返回已经登录的会话:return: 已经登录的会话(session)"""#设置login_url = 'http://xxx.xx.xx.cn/authserver/login?service=http%3A%2F%2F%2F'headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'}#新建会话session=requests.session()#获取登录校验码html=session.post(login_url,headers=headers).textsoup=BeautifulSoup(html,'lxml')lt=soup.find('input',{'name':'lt'})['value']dllt=soup.find('input',{'name':'dllt'})['value']execution = soup.find('input', {'name': 'execution'})['value']_eventId = soup.find('input', {'name': '_eventId'})['value']rmShown = soup.find('input', {'name': 'rmShown'})['value']login_data={'username': input("请输入学号:"),'password': input("请输入密码:"),'btn':'','lt': lt,'dllt': dllt,'execution': execution,'_eventId': _eventId,'rmShown': rmShown}#登录response=session.post(login_url,headers=headers,data=login_data)if response.url=='http://xxx.xx.xx.cn/':print('登录成功!')return session

saveInTXT

def saveInTXT(url, session, title):'''获取单个公告页面的公告并保存到txt:param url: 要获取的页面的url:param session:已经登录的会话:param title:公告标题:return:无'''#将标题转换为可以作为文件名字的形式reg = r'[\/:*?"<>|]'title = re.sub(reg, "", title)path='bullet\\' + title+'.txt'#保存在py文件目录下的bulletin文件夹内,以txt格式保存headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'}'''#测试代码,从文件读取手动获取的公告html页面,单机测试with open('new.txt','r',encoding='utf8') as fin:html=fin.read()'''html=session.post(url,headers=headers).textsoup=BeautifulSoup(html,'lxml')#print(soup.prettify())bulletin_content=soup.find('div', class_='bulletin-content')bulletin_content= ''for p in bulletin_content.find_all('p'):if p.span!=None:#如果p含有一层spantext=str(p.get_text()).strip()bulletin_content+= text + '\n'with open(path,'w',encoding='utf8') as fout:fout.write(bulletin_content)print('“{}”成功保存到{}'.format(title,path))

saveInDB

def saveInDB(url, session, title):'''获取单个公告页面的公告并保存到txt:param url: 要获取的页面的url:param session:已经登录的会话:param title:公告标题:return:无'''headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'}html=session.post(url,headers=headers).textsoup=BeautifulSoup(html,'lxml')bulletin_content=soup.find('div', class_='bulletin-content')bulletin_content= ''for p in bulletin_content.find_all('p'):if p.span!=None:#如果p含有一层spantext=str(p.get_text()).strip()bulletin_content+= text + '\n'#保存到数据库db = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root', db='news', charset='utf8')cursor = db.cursor()cursor.execute("insert into chdnews(`title`,`content`) values('{0}','{1}')".format(title, bulletin_content))db.commit()print('已经成功保存公告到数据库:“{}”'.format(title))

调用

#调用
get_bulletin(10)#爬取10页公告

暂时没有将其通用化,直接将网址写死在函数里面了。

day6进度

  1. 通过调整服务门户的url中的参数来获取通知公告的每一个目录页的url,从而爬取所有公告
  2. 将学习中写的测试代码重新构造整理,添加函数注释,提交任务

python爬虫学习笔记2模拟登录与数据库相关推荐

  1. python爬虫学习笔记 1.9 (Handler处理器 和 自定义Opener)

    python爬虫学习笔记 1.1(通用爬虫和聚焦爬虫) python爬虫学习笔记 1.2 ( HTTP和HTTPS ) python爬虫学习笔记 1.3 str和bytes的区别 python爬虫学习 ...

  2. python爬虫学习笔记3.2-urllib和request练习

    python爬虫学习笔记3.2-urllib和request练习 一.urllib练习 1.百度贴吧案例 需求 分析 手动测试查询流程 观察页面 分析特殊部分 https://tieba.baidu. ...

  3. python爬虫学习笔记 3.9 (了解参考:训练Tesseract)

    python爬虫学习笔记 3.9 (了解参考:训练Tesseract) 参考阅读:训练Tesseract 要使用 Tesseract 的功能,比如后面的示例中训练程序识别字母,要先在系统中设置一 个新 ...

  4. Python爬虫学习笔记 -- 爬取糗事百科

    Python爬虫学习笔记 -- 爬取糗事百科 代码存放地址: https://github.com/xyls2011/python/tree/master/qiushibaike 爬取网址:https ...

  5. python爬虫token_Python入门:模拟登录(二)或注册之requests处理带token请求

    转自http://blog.csdn.net/foryouslgme/article/details/51822209 首先说一下使用Python模拟登录或注册时,对于带token的页面怎么登录注册模 ...

  6. python3爬虫学习笔记之模拟淘宝登录

    准备工作 使用chrome f12调试模式,抓包查看淘宝登录的整个流程,并查看post请求的数据 值得注意的是,淘宝用的是gbk编码 说明 此版本没有处理验证码,只是单纯的登录 具体的流程和实现都在代 ...

  7. Python爬虫学习笔记总结(一)

    〇. python 基础 先放上python 3 的官方文档:https://docs.python.org/3/ (看文档是个好习惯) 关于python 3 基础语法方面的东西,网上有很多,大家可以 ...

  8. 一入爬虫深似海,总结python爬虫学习笔记!

    正文 〇. python 基础 先放上python 3 的官方文档:https://docs.python.org/3/ (看文档是个好习惯) 关于python 3 基础语法方面的东西,网上有很多,大 ...

  9. 一入爬虫深似海,总结python爬虫学习笔记! 1

    正文 〇. python 基础 先放上python 3 的官方文档:https://docs.python.org/3/ (看文档是个好习惯) 关于python 3 基础语法方面的东西,网上有很多,大 ...

最新文章

  1. pytorch nlp 语音识别任务如何进行数据加载
  2. linux内存显示3.54g,为什么WDCP/linux服务器内存一直显示几乎用完了
  3. DBD::mysql::db do failed: Table cl_access was locked with a READ lock and can't be updated
  4. 11 个 Nginx 参数性能优化工作
  5. 【Envi风暴】Envi5.4经典安装图文教程
  6. jzoj4209-已经没有什么好害怕的了【差分】
  7. 3条原则,16个小点,帮你写出一个优秀的对外接口!
  8. MVVM模式下 触发器多条件判断
  9. atmega328p引脚图_ATMEGA328P-AU 8位AVR微控制器
  10. 小米手机开发者模式怎么打开?简单,只要三步
  11. 网页访问报错This request has been blocked; the content must be served over HTTPS.
  12. ninja: error: ‘xxx‘, needed by ‘xxx‘, missing and no known rule to make it
  13. 联想计算机设置恢复出厂,联想电脑恢复出厂设置还原系统攻略
  14. 熬夜肝出 3w 字测试开发学习路线
  15. java:判断字符串的开始或结尾
  16. 多项式函数在某一点处的泰勒展开
  17. ubuntu20.04下好用的截图软件
  18. 第一类公民(First-class Citizen)
  19. 【数据库】完美卸载sql server 2008 r2
  20. 浏览器中利用js打包下载所有类型文件

热门文章

  1. 大华摄像头webplugin.exe插件开发(需要设置固定IP地址,端口号)
  2. node.js从0到0.1
  3. LT Spice XVII无源滤波器设计。
  4. 中国著名电子商务网站网址名单大全
  5. 【Keil】Keil Cx51 编译器中文用户手册介绍
  6. 大学计算机实验报五告,大学计算机实验报告二_相关文章专题_写写帮文库
  7. pip install pandas_profiling报错问题解决方法
  8. 外链转内链php,Typecho:网站外链自动转换内链插件ShortLinks
  9. java语言案例设计猜数游戏
  10. 智能公交电子站牌为你报告实时交通信息,让出行更方便