netCafe 发表于 2018-7-25 15:35

【Python】爬虫如何爬取网站新闻并破解反

本帖最后由 wushaominkk 于 2018-7-26 14:28 编辑

# Python爬取新闻网站并破解反爬

一开始我以为爬取一个新闻网站是很简单的,因为 一般的新闻网站都比较容易爬取。
然而,随着我着手分析之后,开始写代码,运行之后发现并不是那么简单。

需要爬取的新闻网站为http://www.shxz.gov.cn/sites/CSMHXZMH/ViewList2_pg.ashx?ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0

### 分析
思路很简单:
分析网站-->找出每一页的网址规律-->分析每一页包含的新闻链接-->循环批量下载
看起来是不是很简单呀,现在我开始分析每一页网址的页数规律

我分别打开了
第一页的链接
http://www.shxz.gov.cn/sites/CSMHXZMH/ViewList2_pg.ashx?ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0
第二页的链接
http://www.shxz.gov.cn/sites/CSMHXZMH/ViewList2_pg.ashx?page=2&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0
第三页的链接
http://www.shxz.gov.cn/sites/CSMHXZMH/ViewList2_pg.ashx?page=3&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0
通过观察可以发现
> page= 后面的数字就是页码,然后我把后面的页码改为其他数字打开和用原页面跳转到其他页面看到的内容是一样的,所以现在找到每页的网址规律了,后面通过for循环就可以不断的爬取下去
```
for i in range(1,3):
    url="http://www.shxz.gov.cn/sites/CSMHXZMH/ViewList2_pg.ashx?page="+str(i)+"&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0"
```

然后分析每一页的网址,鼠标右键**检查**,然后随便复制一个新闻标题,到页面源码上按Ctr + F查找,找到第一个新闻的标题,下面有一段代码,我点击进去发现直接跳转到第一个新闻界面了,然后我尝试查看看看有多少个这样的网址,我发现有17个,然而每个页面的新闻不重复的是12个,剩下的5个是旁边推荐的内容
>
ViewCon2_pg.ashx?ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&infId=7f2c956f-75b0-4a59-808b-fa72b3307db0&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0这是点击跳转的链接
跳转之后的网址为
http://www.shxz.gov.cn/sites/CSMHXZMH/ViewCon2_pg.ashx?ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&infId=ce846a98-ed2c-4181-861d-3b6c000b9ba9&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0
只需要找出每个页面的12个ViewCon2_pg.ash········这段代码,然后在前面加上http://www.shxz.gov.cn/sites/CSMHXZMH/ 就是每个新闻的网址,所以我只需要筛选出每页的12个这段代码即可
观察源代码,选择正则表达式进行筛选
```
pat='<div style=" float:left;"><a class="list13" href="(ViewCon.*?)"'
```


然后我先进行爬取2页看看怎么样
```
import urllib.request
import re

for i in range(1,3):
    url="http://www.shxz.gov.cn/sites/CSMHXZMH/ViewList2_pg.ashx?page="+str(i)+"&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0"
data=urllib.request.urlopen(url).read().decode("utf-8")
pat='<div style=" float:left;"><a class="list13" href="(ViewCon.*?)"'
allurl=re.compile(pat).findall(data)

for j in range(0,len(allurl)):
    print(allurl)
```
然后发现一切运行正常,但是后来我时候会遇到请求失败的情况,远程主机拒绝访问,就是知道我是爬虫行为了,所以要伪装一下,我伪装为浏览器爬取即可
> ConnectionResetError: 远程主机强迫关闭了一个现有的连接。
```
    headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0")
    opener=urllib.request.build_opener()
    opener.addheaders=
    data=opener.open(url).read()
    data2=data.decode("utf-8","ignore")
```
然后一切正常了
设置一下异常处理,就开始爬取了

```
import urllib.request
import re

for i in range(1,3):
    url="http://www.shxz.gov.cn/sites/CSMHXZMH/ViewList2_pg.ashx?page="+str(i)+"&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0"
   
    headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0")
    opener=urllib.request.build_opener()
    opener.addheaders=
    data=opener.open(url).read()
    data2=data.decode("utf-8","ignore")
   
    pat='<div style=" float:left;"><a class="list13" href="(ViewCon.*?)"'
    allurl=re.compile(pat).findall(data2)
    for j in range(0,len(allurl)):
      try:
            print("第"+str(i)+str(j)+"次爬取")
            realurl="http://www.shxz.gov.cn/sites/CSMHXZMH/"+str(allurl)
            file="D:/PyCharm/code/news_shxz_gov/"+str(i)+str(j)+".html"
            urllib.request.urlretrieve(realurl,file)
            print("-------成功-------")
      except urllib.error.URLError as e:
            if hasattr(e,"code"):
                print(e.code)
            if hasattr(e,"reason"):
                print(e.reason)
```

现在一切正常,然后我打开爬取到的文件发现没有内容,我检查代码是没问题的,然后我去检查其中的一个新闻页面源代码,发现数据是经过JavaScript处理的,还真是有反爬的呀。很无奈,再次分析吧

按F12,然后再按F5刷新页面,查看Network
> Content.ashx?infId=908d112a-2520-4c1b-a7f8-9032fed…32&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0
点击到这一行时,点击Preview发现就是我们需要的文章内容,然后右键这一行,Copy-->Copy link address,分析这个真实的网址,然后可以打开多几个不同页数的网址进行分析
JavaScript加载的网址
http://www.shxz.gov.cn/sites/Iframe_ZZTY_cxs/dyn/Content.ashx?infId=908d112a-2520-4c1b-a7f8-9032fedbfe5c&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0
原页面的网址
http://www.shxz.gov.cn/sites/CSMHXZMH/ViewCon2_pg.ashx?ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&infId=908d112a-2520-4c1b-a7f8-9032fedbfe5c&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0
zhi这是第一次处理之后的有效代码
ViewCon2_pg.ashx?ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&infId=908d112a-2520-4c1b-a7f8-9032fedbfe5c&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0

> 然后观察最后的真实网址和原来的对比,发现有效部分是infId=908d112a-2520-4c1b-a7f8-9032fedbfe5c

这个可以决定每个新闻的链接
其他部分是不变的
`realurl= "http://www.shxz.gov.cn/sites/Iframe_ZZTY_cxs/dyn/Content.ashx?"+str(allurl)+"&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0"`

所以一开始筛选出这部分决定行的代码即可,然后我发现这个正则有点难写,所以我直接用for循环遍历去重

最终代码如下

```
# 导入urllib和re库
import urllib.request
import re

# 设置爬取的页数,进行循环爬取
for i in range(1, 3):
    url = "http://www.shxz.gov.cn/sites/CSMHXZMH/ViewList2_pg.ashx?page=" + str(
      i) + "&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0"

    # 模拟浏览器爬取并安装为全局变量 ,爬取所有页面的信息
    headers = ("User-Agent",
               "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0")
    opener = urllib.request.build_opener()
    opener.addheaders =
    data = opener.open(url).read()
    data2 = data.decode("utf-8", "ignore")

    # 设置新闻网址的正则表达式去掉重复链接并提取每个新闻页面的网址,最后提取有用的部分
    pat = '40e8d70ae432&(infId.*?)&leftBarId'

    allurl = re.compile(pat).findall(data2)
    # 设置循环,列表输出去重
    for j in range(0, len(allurl)):
      try:
            realurl = "http://www.shxz.gov.cn/sites/Iframe_ZZTY_cxs/dyn/Content.ashx?"+str(allurl)+"&ctgId=fe188544-e1fe-4230-b754-40e8d70ae432&leftBarId=08f6f7e1-badb-49fd-8da9-009f8dcc14a0"
            print("第" + str(i) + str(j) + "次爬取")
            #设置保存文件本地路径并命名爬取到的每个文件
            file = "D:/PyCharm/code/news_shxz_gov/" + str(i) + str(j) + ".html"
            #开始爬取下载
            urllib.request.urlretrieve(realurl, file)
            print("-------成功-------")
      #设置异常处理
      except urllib.error.URLError as e:
            if hasattr(e, "code"):
                print(e.code)
            if hasattr(e, "reason"):
                print(e.reason)
```


然后我打开每个爬取到的本地文件,发现正常了,这个网站还有点反爬,需要设置伪装,因为还没有大量爬取,所以不知道需不需要设置代{过}{滤}理服务器,不过也是很简单的,增加几行代码即可。
要是需要爬取图片,也可以分开爬取保存即可。
速度方面我测试了爬取速度,感觉还是可以的。

欢迎大家尝试一下,然后让代码更加完善,代码我已经放到我的github上
https://github.com/BitCute/netCafe/blob/master/Python%20Robots/news_shxz_gov.py


大家喜欢python爬虫和数据分析的欢迎和我交流学习

觉得文章好的欢迎打赏点免费的CB或者爱心
老铁给免费评个分呗




netCafe 发表于 2018-7-26 16:32

Ya-KKK 发表于 2018-7-26 16:24
请问一下,我现在有那么一丢丢python基础,然后我以后想往爬虫那边走,我应该怎么学呢,又比较好的方法, ...

这个教程我后续会继续发布的,关注我就可以了。

光是做爬虫是不太建议的,除非你爬虫玩的很好,所有的网站都可以突破

villain0521 发表于 2018-7-26 17:28

关注,学习啊。

ks521 发表于 2018-7-25 15:43

感谢楼主分享

netCafe 发表于 2018-7-25 15:48

ks521 发表于 2018-7-25 15:43
感谢楼主分享

免费评个分老铁

154675361 发表于 2018-7-25 15:48

感谢楼主,学习一下,谢谢

shage 发表于 2018-7-25 15:48

虽然没有自己爬取过,但感觉还是很有意思的

netCafe 发表于 2018-7-25 15:50

shage 发表于 2018-7-25 15:48
虽然没有自己爬取过,但感觉还是很有意思的

大部分的新闻网站都差不多的,掌握一个流程分析就很容易了

maya369 发表于 2018-7-25 15:55

刚开始入门,好好学习下,感谢楼主分享!

netCafe 发表于 2018-7-25 15:58

maya369 发表于 2018-7-25 15:55
刚开始入门,好好学习下,感谢楼主分享!

我后续还会发爬虫教程的,很详细很实用的教程,最近还在写着,比较长

netCafe 发表于 2018-7-25 15:59

netCafe 发表于 2018-7-25 15:58
我后续还会发爬虫教程的,很详细很实用的教程,最近还在写着,比较长

喜欢的,可以收藏关注我,觉得好的欢迎赏点CB和热心

oopsw 发表于 2018-7-25 16:09

大佬,膜拜
页: [1] 2 3 4 5 6
查看完整版本: 【Python】爬虫如何爬取网站新闻并破解反