不知道网页链接如何爬取数据(一)

前言:有些时候,我们在查一些比较老的数据,由于网站升级,或者改版之类的,我们无法得到我们想要数据的网址,也就无法爬取数据,下面,我将带大家一起来分析一下自己的案例。

  1. 明确需求
    背景:在网上搜自己的名字,居然找到一份文档,大概是这样的样子2015年普通高校招生录取名单公示(五) (sxkszx.cn) 然后就顺腾摸瓜,想找到全部的数据——2015年全部的数据

  2. 查找数据
    刚开始,由于找到了网站,2015年普通高校招生录取名单公示(五) (sxkszx.cn),网址是http://www.sxkszx.cn/,我想在网站搜索,但是发现网站没有搜索功能,而且,更要命的是,这个每一页,没有上一页,下一页的链接,这样我们就找不到相关联的数据。
    而且,我们发现,网址的拼接也是很奇怪,http://www.sxkszx.cn/news/2015722/n82552675.html,news代表新闻,2015722代表发布日期,后面的n82552675就很奇怪,如果改成n82552676则会404,也就是无法单纯的修改最后一位来完成地址的模拟

  3. 使用搜索引擎增强搜索力度
    现在进入了困境,我们无法在该网站查找。不过我们可是使用
    2015年普通高校招生录取名单 site:sxkszx.cn
    来进行网站的查找,这样是使用搜索引擎来进行该网站的搜索,在百度地址栏输入搜索即可。
    然后我们会找到

    image.png

    很多数据被找到了,然后我们分析一下,发现其中缺少了一些公示,这意味这数据不太完整。

  4. 网站地址分析 + 试探
    现在问题又回到了原点,我们不知道网页的网址,那么就无法爬取数据。但是,现在要比最开始好很多,因为现在除了录取名单五以外,还多了很多,以供我们分析。

    • 整理一下,来分析一下数据的异同
image.png

为了能够看出其中的异同,我把数据一行一行列了出来,然后行号就是公示名单的数字标号(空缺部分表示目前未知的网站链接)

现在分析一下网址,我们发现,最后四位数字好像是递增的


image.png

对,这有点像是,新闻在数据库中存储的编号id,意味着这是第2669篇新闻,那么,第2670篇新闻的网址应该是怎样的呢?
推测如下

http://www.sxkszx.cn/news/日期/n四位不知名数字2670
且日期应当是在2015.7.22当天,或者之后

讲道理,我们这里应该要分析 四位不知名数字 的含义,或者讨论它是如何生成的,但是笔者想了很多,都没能猜到,之前猜测或者与时间/文章名字/等等,但是都不太对,总之没能猜到。

  • 由于我们没猜到,所以我们有一个最朴素的想法,我们遍历0000-9999不就可以了吗?找到那个可以正确返回的链接
    对,这个想法很正确。
下面的这一段代码,返回了一个列表,列表中包含了从0000-9999的所有可能的网址链接
def gene_urls():
    base_url = "http://www.sxkszx.cn/news/"
    date = "2015820"
    newsId = "2745"
    urls = []
    for i in range(1, 10000):
        s = str(i).zfill(4)
        url = base_url + date + "/n" + s + newsId + ".html"
        urls.append(url)
    return urls

写到这里,大家可能觉得,这不很简单吗?直接

for url in urls:
  response = requests.get(url)
  if response.status.code == 200:
      print url
      break

但是,这是很朴素的单线程,我们做一个计算
我们大概空缺的是

日期     新闻id
722      2675
723      2676
...         
83

         ...
         2696

我们发现,一次尝试,都要花费很长的时间,如果我们想要全部试探,需要很长的时间,且,requests要不断断开,建立连接,花销很大。

下面,我们尝试多线程。
下面是一份很长的代码,大家不用关心具体怎么实现的,只要知道
single_thread 代表单线程
multi_thread 代表多线程
即可

# 不断尝试url,当返回不是404,则加入my_urls.txt中

import requests
import threading
import requests.adapters
import time

base_url = "http://www.sxkszx.cn/news/"
date = "2015722"
newsId = "2678"

# f = open("my_urls.txt", 'w+')

flag = 0
# count = 0


def gene_urls():
    urls = []
    for i in range(1, 10000):
        s = str(i).zfill(4)
        url = base_url + date + "/n" + s + newsId + ".html"
        urls.append(url)
    return urls


def test_url(url):
    # response = requests.get(url=url, timeout=30)
    # if response.status_code == 200:
    #     print(url)

    # try:
    #     with requests.get(url, timeout=5) as r:
    #         if r.status_code == 200:
    #             flag = 1
    #             print(url)
    # except:
    #     print("处理异常中...")
    #     time.sleep(5)
    global flag
    if flag == 0:
        response = None
        global count
        try:
            # 设置重连次数
            requests.adapters.DEFAULT_RETRIES = 5
            s = requests.session()
            # 设置连接活跃状态为False
            s.keep_alive = False
            response = requests.get(url, stream=False, timeout=10)
            if response.status_code == 200:
                flag = 1
                print(url)
            # 关闭请求  释放内存
            response.close()
            del (response)
        except Exception as indentfier:
            time.sleep(5)


def single_thread(need_test_urls):
    for url in need_test_urls:
        global flag
        if flag == 0:
            test_url(url)
        else:
            break


def multi_thread(need_test_urls):
    threads = []
    for url in need_test_urls:
        threads.append(
            threading.Thread(target=test_url, args=(url,))
        )

    for thread in threads:
        thread.start()

    for thread in threads:
        thread.join()

    print("ok")


if __name__ == "__main__":
    u = gene_urls()
    multi_thread(u)
    # single_thread(u)

但是问题到这里还没有结束,尽管编写上面的代码,已经踩了很多的坑,包括 如requests未断开;未手动断开(采用with 语句,自动断开会导致他会慢慢断开,还是会报错,max tries,服务器中止...);
但是新的问题又来了,我发现这个代码在有的 日期 + 新闻id上可以运行出结果来,有的则不会,具体原因我也不太清楚,评论区的小伙伴有知道的,可以告诉一下我,谢谢~

  1. scrapy框架的使用
    最后的最后,我实在受不了了,我大概明白,应该是并发的时候,导致requests的连接无法断开,或者断开需要时间,但是还没有断开的这个期间,新的请求已经发送了,这样就会有一部分请求是没有效果的,也就是一部分链接被卡掉了。

而这个,是目前的我所解决不了的。

于是我想着试一下scrapy,因为我之前听过scrapy,但是没有用过,想着用它来解决并发问题,会不会好点。

先说实验结果,最终成功解决了并发问题,对于每一个 日期 + 新闻id 所产生的链接列表,大概在1mins内可以得到结果,已经算是很快了。

再说下去,就要讲scrapy框架了,但是现在我好饿,我先去吃个饭饭,宝宝饿了

你可能感兴趣的:(不知道网页链接如何爬取数据(一))