首页 > 编程语言 > 详细

抓取一个网站全部的网页URL--Python、爬虫

时间:2021-06-02 15:18:47      阅读:16      评论:0      收藏:0      [点我收藏+]

要获得一个网站所有的网页URL,思路很简单,就是一遍遍分析新得到的网页中有哪些URL,然后不断重复的。

下面以抓取CSDN为例:

首先是一些辅助用的函数:

 1 def getResponse(url):# 使用requests获取Response
 2     headers = {
 3         User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
 4     }
 5     response = requests.get(url=url, headers=headers)
 6     return response
 7 
 8 def getHTMLBySelenium(url):# 使用selenium获取页面的page_text
 9     try:
10         chrome_options =Options()
11         chrome_options.add_argument(--headless)
12         browser = webdriver.Chrome(executable_path=C:/Users/Administrator/Desktop/chromedriver_win32/chromedriver.exe, options=chrome_options)
13         browser.get(url)
14         time.sleep(2)
15         page_text = browser.page_source
16         browser.quit()
17         return page_text
18     except Exception as e:
19         return ‘‘
20     
21 def getBlog(url):# 获取页面内容  
22     try:
23         page_text = getHTMLBySelenium(url)
24         tree = etree.HTML(page_text)
25         allText = tree.xpath(//body//text())
26         text = \n.join(allText)
27         title = url.replace(/, _)
28         title = title.replace(., _)
29         title = title.replace(:, _)
30         with open(全站/ + title + .txt, w, encoding=utf-8) as fp:
31             fp.write(text)
32     except Exception as e:
33         return

提取一个页面中包含的所有其他页面的URL,具体网站具体分析,这里是CSDN的获取方式:

def getLinks(url):
    try:
        page_text = getHTMLBySelenium(url)
        tree = etree.HTML(page_text)
        all_href = tree.xpath(//a)
        links = []

        for href in all_href:
            link = href.xpath(./@href)
            if len(link) == 0:
                continue
            link = link[0]
            if link.startswith(https://blog.csdn.net):
                links.append(link)
        return links
    except Exception as e:
        return []

下面就是递归获取页面URL的过程,先看一段简单的代码:

urls = set()# 存储已经被操作过的URL
temp1 = set()# 存储正在被操作的URL
temp2 = set()# 存储新获取的URL

temp1.add(url)# 程序最开始的分析的页面,可以是网站首页URL

while temp1:# temp1不为空则程序一直运行
    for url in temp1:
        if url in urls:# url在urls 代表这条url已经被处理
            continue
        doSomeThing(url)# 处理url
        for link in getLinks(url):# 分析url表示的页面中有哪些其他的URL
            if link in urls:
                continue
            if link in temp2:
                continue
            temp2.add(link)
    # temp1中url处理完毕
    # 将temp2内容赋给temp1,并清空temp2
    temp1 = temp2.copy()
    temp2.clear()

从上述代码可以看到整个程序的运行逻辑,但在具体使用时有一些需要注意的问题:

首先是我们用什么保存获取的链接,我最开始使用的是 set 并将urls,temp1,temp2分别用一个文本文件做备

份,因为我不知道程序会在那个节点出问题,用文本保存后可以避免程序出问题后要重头开始运行代码,这也

是上面的辅助函数我都用 try ... except... 的原因。

按照上述思路我完成了第一版的代码,set + 文本文件,然后程序在周末跑了两天之后,我周一发现程序把电

脑内存跑满了(win10 + 16G内存)电脑卡死了,然后强制关机重启之后我看了一下存储URL的文件,程序最

外层循环大概运行到第四次,temp2中有几十万条URL。

既然内存不够,接下来我就想将URL存储到数据库中,然后我选择用MySQL代替set存储URL,仍然用文本做

备份。

下面是这一版本的代码,如果运行两天之后程序没出现内存的问题,这个随笔就不会再更新:

# ---- 用pymysql 操作数据库
def get_connection():
    conn = pymysql.connect(host=host, port=port, db=db, user=user, password=password)
    return conn

#打开数据库连接
conn = get_connection()

cnt = 1
loop = 2
cursor = conn.cursor()
cursor1 = conn.cursor()
cursor2 = conn.cursor()

while True:
    print(fLoop {loop})
    loop += 1
    # 遍历temp1
    cursor1.execute("select * from csdn_temp1")
    while True:
        temp1Res = cursor1.fetchone()
        # temp1 遍历完成
        if temp1Res is None:
            #表示已经取完结果集
            break
        print (temp1Res)
        url = temp1Res[0]
        url = re.sub([\u4e00-\u9fa5], ‘‘, url)
        cursor.execute("select * from csdn_urls where url = %s", [url])
        urlsRes = cursor.fetchone()
        # 已经抓过这一条链接 continue
        if urlsRes is not None:
            continue
        #if cnt % 100 == 0:
            #print(url)
        cnt += 1
        sql = "insert ignore into csdn_urls values(%s)"        
        cursor.execute(sql,(url))
        conn.commit()
        with open(urls.txt, a, encoding=utf-8) as fp:
            fp.write(url)
            fp.write(\n)
        getBlog(url)
        links = getLinks(url)
        #toTemp2Urls = []
        for link in links:
            # 已经抓过这一条链接 或者 temp2 已经有了这一链接 continue
            cursor.execute("select * from csdn_urls where url = %s", [link])
            urlsRes = cursor.fetchone()
            if urlsRes is not None:
                continue
            cursor2.execute("select * from csdn_temp2 where url = %s", [link])
            temp2Res = cursor2.fetchone()
            if temp2Res is not None:
                continue
            #toTemp2Urls.append(link)
            sql = "insert ignore into csdn_temp2 values(%s)"
            link = re.sub([\u4e00-\u9fa5], ‘‘, link)
            cursor2.execute(sql,(link))
            conn.commit()
            with open(temp2.txt, a, encoding=utf-8) as fp:
                fp.write(link)
                fp.write(\n)
        #sql="insert ignore into csdn_temp2 values(%s)"
        #cursor2.executemany(sql,toTemp2Urls)
        conn.commit()
        #toTemp2Urls = []        
    conn.commit()
    cursor.execute("rename table csdn_temp1 to csdn_temp")
    conn.commit()
    cursor.execute("rename table csdn_temp2 to csdn_temp1")
    conn.commit()
    cursor.execute("rename table csdn_temp to csdn_temp2")
    conn.commit()
    # 删除temp2数据
    cursor.execute("delete from csdn_temp2")
    conn.commit()
    os.rename(temp1.txt, temp3.txt)
    os.rename(temp2.txt, temp1.txt)
    os.rename(temp3.txt, temp2.txt)
    with open(temp2.txt, w, encoding=utf-8) as fp:
        fp.write(‘‘)

在写上述代码时,我遇到了一个问题,表改名后没有及时commit,使得我之前第一版抓的几十万条URL清

空了,而且备份用的文本文件也清空了。修改完之后得到了上述代码。

整个代码的调试过程以及写代码时的思路可以在我的GitHub上看jupyter文件。

抓取一个网站全部的网页URL--Python、爬虫

原文:https://www.cnblogs.com/lnlin/p/14840078.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!