一、前言
其实爬取页面的思路都差不多,观察爬取页面源码,获取页面内容,根据源码的格式规律将自己需要的内容提取出来,提取后美化输出或者保存!
之前写过了如何爬取淘宝和京东的评论,其实这个可以不写的!!但是又遇到坑了所以还是写下来,记录一下错误!!
二、代码与问题
先上代码再说一下自己遇到的问题!
# -*- coding:utf-8 -*-
import requests
from requests.exceptions import RequestException
import re
import json
import time
from multiprocessing import Pool
"""
url= 'https://maoyan.com/board/4'
repsponse = requests.get(url)
print(repsponse.headers['content-type'])
print(repsponse.encoding)#response内容的编码
print(repsponse.apparent_encoding)#response headers里设置的编码
print(requests.utils.get_encodings_from_content(repsponse.text))#response返回的html header标签里设置的编码
"""
def get_url(url):
try:
#说明headers信息,不然一下就403错误了!
heards = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
#获取页面信息
response = requests.get(url,headers=heards)
#页面返回的status_code码为200则是爬取成功
if response.status_code == 200:
#声明页面返回内容的编码格式,不然一般是ISO-8859-1,就乱码了
response.encoding = 'utf-8'
return response.text
return print("爬取失败")
except RequestException:
return print("爬取失败")
def parge_html(html):
#编写正则表达式的格式
#compile() 函数将一个字符串编译为字节代码
pattern = re.compile('<dd>.*?board-index.*?(\d+).*?name.*?<a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">'
+'(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(\d+)</i>.*?</dd>',re.S)
#利用正则表达式获取需要的内容
items = re.findall(pattern,html)
#print(items)
#将内容转化为一个字典使其更容易观看
for item in items:
yield{
'index':item[0],
'name':item[1],
'star':item[2].strip()[3:], #strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
'time':item[3][5:],
'score':item[4]+item[5]
}
def write_to_file(content):
with open('result1.txt', 'a', encoding='utf-8') as f:
#ensure_ascii=False,说明输出的内容不要用ASCII编码,这样结果才是中文
f.write(json.dumps(content,ensure_ascii=False) + '\n') #利用json.dumps将字典转为字符串
f.close()
def main(offset):
#切换页面观察URL的变化
url = 'https://maoyan.com/board/4?offset=' + str(offset)
html = get_url(url)
for item in parge_html(html):
print(item)
write_to_file(item)
#print(html)
if __name__ == "__main__":
#单线程爬取
"""
for i in range(10):
time.sleep(10)
main(i*10)
"""
#多线程
pool = Pool(processes = 10) #默认的话进程数为cpu_count()的值
pool.map(main,[i*10 for i in range(10)])
问题1:
我最开始写的是爬取一页的电影内容,没有用正则表达式转化提取,但是输出的内容是乱码的!
既然乱码就是编码问题了,由于我是已经声明utf-8的编码模式了,我以为是软件问题,我是用pycharm(第一次用我也不知道它初始编码是什么,之前一直用Spyder),我查了一下怎么修改pycharm的编码,file—>settings—>Editor—>File Encoding,一看那里有一个是gbk,我就都改为了utf-8!
但是重新输出后还是乱码!!
在网上找了好久,终于看到有一篇说到点了,其他大部分要么教我修改pycharm编码要么在程序一开始声明utf-8但是都没用!
原来是因为在你调用Response.text时对响应进行解码,如果http头部有声明则基本上按声明进行解码,没用它就会猜!使用默认的 ISO-8859-1解码,有时http头部声明了也还是按照这个解码!
print(repsponse.encoding)#response内容的编码
print(repsponse.apparent_encoding)#response headers里设置的编码
print(requests.utils.get_encodings_from_content(repsponse.text))#response返回的html header标签里设置的编码
可以输入上面的代码看一下是不是编码出问题,我的输出是:ISO-8859-1,utf-8,utf-8请求返回的内容变成了ISO-8859-1肯定乱码!
可以在获取内容后先输入:
response.encoding = 'utf-8'
声明请求返回内容是utf-8编码。
问题2:
问题1解决后我又爬了一次!这次没有乱码,但是因为我在调整编码的时候一直测试一直爬,猫眼觉得我的请求很可疑!禁止了我的请求,出现了403错误!
这个通过增加一个头部信息就好了,之前淘宝比较严格,头部信息比较多。这次就加了一个请求的浏览器类型就可以了!
问题3:
问题2解决后,我接着完善,刚刚是爬取一页,现在是十页!但是又出问题了爬的太频繁太快被要求验证身份了,也就是类似拼图,但是我爬取的内容还没完呢!少了一页,所以我又加了睡眠信息,每十秒爬一次,终于成功了!这是单线程!
接下来是多线程爬取:多线程一般默认是cpu_count()数,我的是8,但是我自己定义开了十个进程。
天下武功唯快不破!!!用了十个进程秒爬,估计猫眼没反应过来,最后爬取内容缺了一个而已!
但是多线程有一个缺点,就是爬取的内容不是按顺序的,本来是top100的电影从1-100,多线程的话内容有点乱!但是问题不大,因为它很快就好了。
参考:https://www.bilibili.com/video/BV1Si4y1s7S4?p=14
https://www.runoob.com/python/python-func-compile.html
https://www.runoob.com/python/att-string-strip.html
https://www.cnblogs.com/biangbiang/archive/2013/02/19/2916780.html
https://blog.csdn.net/a491057947/article/details/47292923
https://blog.csdn.net/weixin_43877278/article/details/103880644