一、背景

疫情期间,每天需要搜集新冠肺炎相关新闻,编写了一个python脚本用户爬取新浪网相关新闻

二、实例解析

  • 模块:requests、BeautifulSoup、re
  • url:https://search.sina.com.cn/?q=新冠&c=news&sort=time

    1.初始化

  • 定义一个GetNews类,在init中写入初始化参数

    1. class GetNews:
    2. def __init__(self,keyword,name):
    3. self.headers={
    4. '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 Edg/88.0.705.74',
    5. 'Referer':'https://search.sina.com.cn/'
    6. }
    7. self.keyword=keyword
    8. self.txtname=name
    9. self.news_url=[] #存储每条新闻的url
    10. self.news_title=[] #存储每条新闻的标题
    11. self.news_content=[] #存储新闻内容
    12. self.news_time=[] #存储新闻的发表时间
    13. self.page_cout=0 #搜索结果的页码

    2.获取搜索结果的页码

image.png

  • 如上图所示,新浪的搜索结果是分页保存的,先获取搜索结果的总页数,可用于后续爬取所以相关新闻。

    1. def get_page_cout(self):
    2. url = 'https://search.sina.com.cn/?q={0}&c=news&from=channel&ie=utf-8'.format(self.keyword) #查找的关键字url
    3. response = requests.get(url)
    4. response.encoding = 'utf-8'
    5. html =response.text
    6. soup =BeautifulSoup(html,'lxml')
    7. try:
    8. page = soup.select('.l_v2')[0].text
    9. except Exception as e:
    10. page = ''
    11. print(e)
    12. if page !='' :
    13. purl = ''
    14. self.page_cout = re.findall(r'[0-9]\d*',page)
    15. for x in self.page_cout:
    16. purl = purl+x
    17. print(purl)
    18. self.page_cout = int(purl)//20 +1 #总的页数
    19. else:
    20. self.page_cout = 0
    21. return self.page_cout

    3.获取新闻页的具体链接

  • 点击搜索结果【第二页】后,url变为https://search.sina.com.cn/?q=%e6%96%b0%e5%86%a0%e8%82%ba%e7%82%8e&c=news&from=&col=&range=all&source=&country=&size=10&stime=&etime=&time=&dpc=0&a=&ps=0&pf=0&page=2

  • 检查网页元素,找到新闻链接保存在h2下的a标签中
  • 利用a.text和a.get(‘href’)分别获取新闻的标题和链接

    1. #获取新闻链接
    2. def get_news_url(self):
    3. url = 'https://search.sina.com.cn/?q={0}&c=news&from=&col=&range=all&source=&country=&size=10&stime=&etime=&time=&dpc=0&a=&ps=0&pf=0&page={1}'
    4. count =input('共找到{}页信息,输入需要爬取的页数(输入【a】将爬取全部):'.format(self.page_cout))
    5. if count=='a':
    6. count = self.page_cout
    7. print('开始爬取新闻链接....')
    8. for x in range(1,int(count)):
    9. url=url.format(self.keyword,x)
    10. req=requests.get(url=url)
    11. req.encoding='utf-8'
    12. soup=BeautifulSoup(req.text,'lxml')
    13. div=soup.find_all('h2')
    14. a_bs=BeautifulSoup(str(div),'lxml')
    15. a=a_bs.find_all('a')
    16. for each in a:
    17. self.news_title.append(each.text)
    18. self.news_url.append(each.get('href'))

    3.获取新闻页的具体内容

  • 利用检查元素找到新闻内容和时间具体位置,再利用soup.select和re.findall去查找获取就行了

    1. #获取新闻内容
    2. def get_news_content(self):
    3. print('开始爬取新闻内容....')
    4. for url in self.news_url:
    5. req=requests.get(url)
    6. req.encoding='utf-8'
    7. soup=BeautifulSoup(req.text,'lxml')
    8. #获取新闻发布时间
    9. reg_time=soup.select('div.date-source>span.date')
    10. str_time=re.findall('<span class="date">(.*?)</span>',str(reg_time),re.S)
    11. self.news_time.append(str_time)
    12. #获取新闻内容
    13. reg_content=soup.select('#article')
    14. data=re.findall('<p cms-style="font-L">(.*?)</p>',str(reg_content),re.S) #re.S参数,多行匹配
    15. str_data=''.join(data).replace('\u3000\u3000','\n\u3000\u3000') #将data中的数组拼成一个字符串,以|u3000全角空白符换行显示
    16. res=r'<font cms-style=".*">.*?</font>'
    17. if re.search(res,str_data) !='':
    18. str_data=re.sub(res,'',str_data) #去掉内容中多余的标签
    19. self.news_content.append(str_data)

    4.保存新闻内容

  • 将新闻的标题、时间、内容写入txt文档中

    1. def writer(self):
    2. print('开始写入文本....')
    3. write_flag = True
    4. with open(self.txtname, 'w', encoding='utf-8') as f:
    5. for i in range(len(self.news_title)):
    6. if self.news_content[i]!='':
    7. f.writelines(self.news_title[i])
    8. f.writelines('\n')
    9. f.writelines(self.news_time[i])
    10. f.writelines(self.news_content[i])
    11. else:
    12. continue
    13. f.write('\n\n')
    14. f.close()

    5.运行

    1. if __name__=='__main__':
    2. keyword='新冠肺炎'
    3. name='0301.txt'
    4. gn=GetNews(keyword,name)
    5. gn.get_page_cout()
    6. gn.get_news_url()
    7. gn.get_news_content()
    8. gn.writer()
    9. print('sucsuss')

    三、小结

  • 新浪网的新闻页HTML格式不统一,获取的新闻链接、内容的select位置不统一,所以本文中的代码只爬取了

    (.*?)

    这个位置中的内容,不是这个格式就找不到,如果要匹配所有内容,修改下正则表达式就可以了。