抓取⼀个⽹站全部的⽹页URL--Python、爬⾍
要获得⼀个⽹站所有的⽹页URL,思路很简单,就是⼀遍遍分析新得到的⽹页中有哪些URL,然后不断重复的。
下⾯以抓取CSDN为例:
⾸先是⼀些辅助⽤的函数:
1def 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 = (url=url, headers=headers)
6return response
7
8def getHTMLBySelenium(url):# 使⽤selenium获取页⾯的page_text
9try:
10 chrome_options =Options()
11 chrome_options.add_argument('--headless')
12 browser = webdriver.Chrome(executable_path='C:/Users/Administrator/Desktop/chromedriver_', options=chrome_options)
13 (url)
14 time.sleep(2)
15 page_text = browser.page_source
16 browser.quit()
17return page_text
18except Exception as e:
19return''
20
21def getBlog(url):# 获取页⾯内容
22try:
23 page_text = getHTMLBySelenium(url)
24 tree = etree.HTML(page_text)
25 allText = tree.xpath('//body//text()')
26 text = '\n'.join(allText)
27 title = place('/', '_')
28 title = place('.', '_')
29 title = place(':', '_')
30 with open('全站/' + title + '.txt', 'w', encoding='utf-8') as fp:
31 fp.write(text)
32except Exception as e:
33return
提取⼀个页⾯中包含的所有其他页⾯的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('blog.csdn'):
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
html制作一个网页
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 = py()
temp2.clear()
从上述代码可以看到整个程序的运⾏逻辑,但在具体使⽤时有⼀些需要注意的问题:
⾸先是我们⽤什么保存获取的链接,我最开始使⽤的是 set 并将urls,temp1,temp2分别⽤⼀个⽂本⽂件做备
份,因为我不知道程序会在那个节点出问题,⽤⽂本保存后可以避免程序出问题后要重头开始运⾏代码,这也
是上⾯的辅助函数我都⽤ try ... 的原因。
按照上述思路我完成了第⼀版的代码,set + ⽂本⽂件,然后程序在周末跑了两天之后,我周⼀发现程序把电
脑内存跑满了(win10 + 16G内存)电脑卡死了,然后强制关机重启之后我看了⼀下存储URL的⽂件,程序最
外层循环⼤概运⾏到第四次,temp2中有⼏⼗万条URL。
既然内存不够,接下来我就想将URL存储到数据库中,然后我选择⽤MySQL代替set存储URL,仍然⽤⽂本做
备份。
下⾯是这⼀版本的代码,如果运⾏两天之后程序没出现内存的问题,这个随笔就不会再更新:# ---- ⽤pymysql 操作数据库
def get_connection():
conn = t(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(f'Loop {loop}')
loop += 1
# 遍历temp1
while True:
temp1Res = cursor1.fetchone()
# temp1 遍历完成
if temp1Res is None:
#表⽰已经取完结果集
break
print (temp1Res)
url = temp1Res[0]
url = re.sub('[\u4e00-\u9fa5]', '', 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)"
connmit()
with open('', 'a', encoding='utf-8') as fp:
fp.write(url)
fp.write('\n')
getBlog(url)
links = getLinks(url)
#toTemp2Urls = []
for link in links:
# 已经抓过这⼀条链接或者 temp2 已经有了这⼀链接 continue
urlsRes = cursor.fetchone()
if urlsRes is not None:
continue
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)
connmit()
with open('', 'a', encoding='utf-8') as fp:
fp.write(link)
fp.write('\n')
#sql="insert ignore into csdn_temp2 values(%s)"
#utemany(sql,toTemp2Urls)
connmit()
#toTemp2Urls = []
connmit()
connmit()
connmit()
connmit()
# 删除temp2数据
connmit()
with open('', 'w', encoding='utf-8') as fp:
fp.write('')
在写上述代码时,我遇到了⼀个问题,表改名后没有及时commit,使得我之前第⼀版抓的⼏⼗万条URL清空了,⽽且备份⽤的⽂本⽂件也清空了。修改完之后得到了上述代码。
整个代码的调试过程以及写代码时的思路可以在我的上看jupyter⽂件。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论