Qakatayama
@Qakatayama (tara chan)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Pythonでスクレイピングした結果をPDF出力する際、自動で改行させたい

解決したいこと

GoogleColab 上でPythonを使用し,Yahooニュース各記事のタイトルと本文を
スクレイピングするコードを書きました。スクレイピング自体はうまく出来ているようです。

ただし、それをreportlabでPDFファイルとして出力する際、長文だと改行されないため、
一行だけしか出力できませんでした。

自動で改行させ、全文PDFに出力したいと思います。
解決方法を教えて下さい。
(当方、Python歴1か月の初心者なので、できるだけ平易な表現をして頂ければ幸いです)

発生している問題・エラー

下記は出力したPDFです。
改行されないため、一行だけで終わり、全文出力されません。
キャプチャ.PNG

該当するソースコード

!pip install reportlab

import requests
from bs4 import BeautifulSoup
import re
from google.colab import files
import datetime as dt
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.units import inch, mm, cm
from reportlab.platypus import Table, TableStyle,Paragraph
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.styles import getSampleStyleSheet

ttf_file = '/content/drive/MyDrive/ipaexg.ttf' #フォントのパスを指定する
pdfmetrics.registerFont(TTFont('IPAexGothic', ttf_file))#フォントを登録する
now = dt.datetime.now(dt.timezone(dt.timedelta(hours=9))) # 日本時刻

pdf = canvas.Canvas(now.strftime('%Y%m%d_%H%M')+'News.pdf', pagesize=(210 * mm, 297 * mm)) # A4縦のCanvasを作成

url = 'https://news.yahoo.co.jp/topics'
res = requests.get(url)
soup = BeautifulSoup(res.text,"html.parser")

elems = soup.find_all(href=re.compile("news.yahoo.co.jp/pickup"))
pickup_links = [elem.attrs['href']for elem in elems]

for pickup_link in pickup_links: #一覧のリンクを順に処理

pickup_res = requests.get(pickup_link)
pickup_soup = BeautifulSoup(pickup_res.text, "html.parser")

pickup_elem = pickup_soup.find("p", class_="sc-fZNsvg drNWzQ")    
news_link = pickup_elem.contents[0].attrs['href']

news_res = requests.get(news_link)
news_soup = BeautifulSoup(news_res.text, "html.parser")

Name=news_soup.title.text
URL=news_link

detail_text = news_soup.find(class_=re.compile("Directlink"))
if hasattr(detail_text, "text"):
  Text=detail_text.text
else: 
  Text=''

styles = getSampleStyleSheet()
Text1 = Paragraph(Text,style=styles["Normal"])
font_size = 10
pdf.setFont('IPAexGothic', font_size)

pdf.drawString(10 * mm, (297 - 10) * mm, Name)
pdf.drawString(10 * mm, (297 - 20) * mm, URL)
pdf.drawString(10 * mm, (297 - 30) * mm, Text1.text)

pdf.showPage()

pdf.save()

自分で試したこと

*ParagraphStyleを使えば上手くできると思い、他の方のホームページを参考に
 試行してみたのですが、やり方が悪いのか上手くいきませんでした。

0

2Answer

@Daru-IBN5100

ご回答ありがとうございます。
試行錯誤した結果、拙いながらも下記コードで改行して
結果出力することができました。

※私もPython初心者なので、必要ない処理があるかもしれません。
※googlecolab上で実施。reportlabインストール後下記実行

import os,sys
import requests
from bs4 import BeautifulSoup
import re
from google.colab import files
import datetime as dt
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.units import inch, mm, cm
from reportlab.platypus import Table, TableStyle,Paragraph,SimpleDocTemplate, Spacer, Image
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.styles import getSampleStyleSheet

ttf_file = '/content/drive/MyDrive/ipaexg.ttf'
pdfmetrics.registerFont(TTFont('IPAexGothic', ttf_file))
now = dt.datetime.now(dt.timezone(dt.timedelta(hours=9)))

filename = now.strftime('%Y%m%d_%H%M')+'News.pdf'
pdf = canvas.Canvas("/content/drive/MyDrive/YahooNews.pdf", pagesize=(210 * mm, 297 * mm))
url = 'https://news.yahoo.co.jp/topics'
res = requests.get(url)
soup = BeautifulSoup(res.text,"html.parser")

elems = soup.find_all(href=re.compile("news.yahoo.co.jp/pickup"))
pickup_links = [elem.attrs['href']for elem in elems]

for pickup_link in pickup_links:

pickup_res = requests.get(pickup_link)
pickup_soup = BeautifulSoup(pickup_res.text, "html.parser")

pickup_elem = pickup_soup.find("p", class_="sc-fZNsvg drNWzQ")    
news_link = pickup_elem.contents[0].attrs['href']

news_res = requests.get(news_link)
news_soup = BeautifulSoup(news_res.text, "html.parser")

Name=news_soup.title.text
URL=news_link

detail_text = news_soup.find(class_=re.compile("Directlink"))
if hasattr(detail_text, "text"):
  Text=detail_text.text
else: 
  Text=''

def setStyleParam2J( style ):
    style.fontName = 'IPAexGothic'
    style.wordWrap  ='CJK'
styles = getSampleStyleSheet()
setStyleParam2J(styles['Normal'])

Text1 = Paragraph(Text,style=styles["Normal"])
font_size = 10
pdf.setFont('IPAexGothic', font_size)

pdf.drawString(10 * mm, (297 - 10) * mm, Name)
pdf.drawString(10 * mm, (297 - 20) * mm, URL)
Text1.wrapOn(pdf, 180*mm, 250*mm)
Text1.drawOn(pdf, 10*mm, 50*mm)


pdf.showPage()

pdf.save()

1Like

Python はあまり詳しくないので、とりあえず試してみたことを載せておきます。

from reportlab.lib.pagesizes import A4, portrait
from reportlab.lib.units import mm
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph
from reportlab.pdfgen import canvas
import textwrap

pdf = canvas.Canvas('example.pdf', pagesize=A4)
width, height = A4

text_A  = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
text_B  = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"

styles = getSampleStyleSheet()
styleBT = styles["BodyText"]

# もしかしたら日本語の時は必要かも?
styleBT.wordWrap = "CJK"

# drawStringではWrapしない
pgText_A = Paragraph(text_A, styleBT)
pdf.drawString(10*mm, (297 - 30)*mm, pgText_A.text)

# drawStringにwrapOnではWrapしない
pgText_A.wrapOn(pdf, 100*mm, 0*mm)
pdf.drawString(10*mm, (297 - 60)*mm, pgText_A.text)

# textwrapで無理やりWrapさせる(※行数オーバー未処理)
drawx = 10*mm
drawy = (297 - 90)*mm
# wrap文字数
wrapw = 60
if len(pgText_A.text) > wrapw:
    wrap_text = textwrap.wrap(pgText_A.text, width = wrapw)
    pdf.drawString(drawx, drawy, wrap_text[0])
    pdf.drawString(drawx, drawy - 5*mm, wrap_text[1])
    pdf.drawString(drawx, drawy - 10*mm, wrap_text[2])
else:
    pdf.drawString(drawx, drawy, pgText_A.text)

# wrapOn&drawOnではWrapする
pgText_B = Paragraph(text_B, styleBT)
pgText_B.wrapOn(pdf, 100*mm, 0*mm)
pgText_B.drawOn(pdf, 10*mm, (297 - 120)*mm)

pdf.showPage()
pdf.save()

詳しくは調べていないですが、なんとなく、Html レンダラを利用している感じがあるので、もしかしたら style の方で調整するやり方もあるかもです。
以上、参考になれば😊

0Like

Your answer might help someone💌